home *** CD-ROM | disk | FTP | other *** search
/ PC Format (UK) 124 / pcfcd124-a.iso / Trial Software / BlitzBasic / Rift2001-05-16 / Rift2 / Celestial Rift v1-1.bb next >
Encoding:
Text File  |  2001-05-16  |  110.6 KB  |  2,037 lines

  1. AppTitle "Celestial Rift - Version 1.1 (C)2001 Myke P" ;what this program will be called in MICROSOFT WINDOWS.
  2.  
  3. ;This makes two CONSTants. These are values which will NOT change at any point in the program, so we set their values now.
  4. Const SCREEN_WIDTH = 800
  5. Const SCREEN_HEIGHT = 600
  6. ;This is the code which tells Blitz what Display Resolution to use on the Graphics Card. The "GRAPHICS" command should always be placed before you do
  7. ;*anything* image-related in your program
  8. Graphics SCREEN_WIDTH,SCREEN_HEIGHT,0,1    ;start the graphics mode at SCREEN_WIDTH by SCREEN_HEIGHT, let Blitz choose the depth (,0) and run full screen (,1)
  9.  
  10. ;more program CONSTants..
  11. Const GAME_AREA_X = 50000    ;these two set the size of the map. You *should* keep them the same, 'cos the radar is square
  12. Const GAME_AREA_Y = 50000    ;but technically, you can change the values to anything you like! ;)
  13. ;the following constants are keyboard "SCAN" codes. Every key on the keyboard has a number. You can get the full list in your Blitz manual.
  14. Const KEY_CLOCKWISE = 25    ;(p)    
  15. Const KEY_ANTICWISE = 24    ;(o)
  16. Const KEY_SPEEDUP = 16        ;(q)
  17. Const KEY_SPEEDDOWN = 30    ;(a)
  18. Const KEY_FIRE = 57            ;(Space)
  19. Const KEY_HYPER = 2            ;(1)
  20. Const KEY_BOOST = 50        ;(m)
  21. Const KEY_CLOAK = 46        ;(c)
  22. Const KEY_QUIT = 1            ;(Escape)
  23. Const KEY_PAUSE = 7            ;(Number 6 on the main keyboard)
  24. Const KEY_DEBUG = 59        ;(F1)
  25. Const KEY_SAVESCREEN = 88    ;(F12)
  26. ;the following constants affect the way the game plays. Feel free to mess with the values..
  27. Const INCR_ROTATE# = 5                ;.. but DON'T touch this, otherwise the game will crash (I only drew the animation frames for 5 degree intervals!)
  28. Const INCR_SPEED# = 0.5
  29. Const INCR_SLOW# = 0.125
  30. Const INCR_BOOSTERS_UP# = 0.025
  31. Const INCR_BOOSTERS_DOWN# = .75
  32. Const INCR_CLOAK_UP#= 0.0125
  33. Const INCR_CLOAK_DOWN# = .25 
  34. Const SPEED_MAX = 25
  35. Const SPEED_MIN = -5
  36. Const ENEMY_MAX_DIST = 5000
  37. Const ENEMY_MIN_DIST = 50
  38. Const DAMAGE_ENEMY_BASH = 2
  39. Const DAMAGE_ENEMY_IS_SHOT = 35
  40. Const DAMAGE_PLAYER_BASH = 2
  41. Const DAMAGE_PLAYER_IS_SHOT = 5
  42. Const SCORE_ENEMYCOLLIDE = 50
  43. Const SCORE_ICONCOLLECT = 200
  44. Const SCORE_ENEMY_IS_SHOT = 400
  45. Const SCORE_ENEMY_IS_DESTROYED = 1500
  46. Const BONUS_BOOSTERS = 48
  47. Const BONUS_SHIELD = 48
  48. Const BONUS_CLOAK = 48
  49.  
  50. ;set up changable variables for game/menu (with initial values, if you like - i.e.: you could just as soon as set them later!)
  51. Global FLAG_GAMEON
  52. Global FLAG_MENUON
  53. Global FLAG_PAUSE
  54. Global FLAG_SAVESCREEN = 0
  55. Global FLAG_DEBUG = 0
  56. Global FLAG_GAMESTARTER
  57. Global PLAYER_SHIELD#
  58. Global PLAYER_BOOSTERS#
  59. Global PLAYER_CLOAK#
  60. Global PLAYER_JUMPS
  61. Global PLAYER_SPEED#
  62. Global PLAYER_ANGLE#
  63. Global PLAYER_X#
  64. Global PLAYER_Y#
  65. Global PLAYER_SCORE
  66. Global PLAYER_SCORE_STR$
  67. Global HI_SCORE
  68. Global HI_SCORE_STR$
  69. Global LAST_SCORE
  70. Global LAST_SCORE_STR$
  71. Global SCORE_FILE
  72.  
  73. Global timer
  74. Global frames
  75. Global starson
  76. Global menu_frame
  77. Global menu_accept_quit
  78. Global game_pause_frame
  79. Global game_accept_pause
  80. Global game_pause_stat
  81. Global gameovercounter
  82. Global gameoverstat
  83. Global whichway
  84. Global hypercount#        ;a "#" symbol after the variable name means it can hold a FLOATING POINT number, i.e.: 190.1234
  85. Global pausecount        ;without the "#" symbol, the variable is, by default, an INTEGER (Whole) number, i.e.: 190
  86. Global cloakon#            ;use the symbols when you are *sure* that you want it to hold specific types of data:
  87. Global frame1            ;# - floating point
  88. Global frame2            ;% - integer (whole number)
  89. Global frame3            ;$ - string (text, i.e.: "MYKE 12345"
  90. Global frame4            ;
  91. Global frame5
  92. Global frame6
  93. Global frame7
  94. Global frame8
  95. Global tempstr$
  96.  
  97. timer = CreateTimer(50) ;create a timer set at 50ms (game speed) - play with this to see how you can increase or decrease the speed of the game.
  98.                         ;this should be set at a speed which will look near enough the same on *every* PC it will be played on.
  99.                         ;My PC (a 733MHz PIII with an nVidia GeForce card) will handle upwards of 150 frames per second, quite happily
  100.                         ;but 'lesser' machines will not. 50, therefore, is quite sensible For a game of this nature, who's minimum system spec
  101.                         ;will be something like a PII 300MHz machine (i.e.: Blitz Basic's minimum spec!)
  102.  
  103. ;NOTE: there's no need to organise your variable declarations, as I have here, into sections. They can appear in any order you like, before the main program begins.
  104. ;I just do this, 'cos it looks right professional! :))))
  105.  
  106. ;picture/animation (and related) variables
  107. Dim game_stars(5)            ;these 3 are ARRAYS. An array is automatically Global, but requires the Keyword (Yellow bit) DIM instead. This means "Dimension".
  108. Dim game_icons(4)            ;the arrays have single dimensions (imagine one straight line of boxes, each that can contain a single variable) 0 to.. (the number in brackets)
  109. Dim game_jumps_level(5)        ;in the case of "game_jumps_level", it has *SIX* containers: 0, 1, 2, 3, 4, 5 and 6.
  110. Global game_background
  111. Global game_radar
  112. Global game_shields
  113. Global game_jumps
  114. Global game_boosters
  115. Global game_cloak
  116. Global game_shields_level
  117. Global game_boosters_level
  118. Global game_cloak_level
  119. Global game_levels
  120. Global game_score
  121. Global game_hiscore
  122. Global game_icon_dot
  123. Global game_player
  124. Global game_player_frame
  125. Global game_player_dot
  126. Global game_enemy1
  127. Global game_enemy1_dot
  128. Global game_scorefont
  129. Global game_bullet_player
  130. Global game_bullet_enemy1
  131. Global game_explosion
  132. Global player_explosion_frame#
  133. Global game_gameover
  134. Global game_paused
  135. Global menu_hiscore
  136. Global menu_lastscore
  137. Global menu_scorefont
  138. Global menu_start
  139. Global menu_start_stat
  140. Global menu_logo
  141. Global menu_credit
  142. Global menu_guildhall
  143. Global menu_thanks
  144. Global menu_quit
  145. Global menu_ship1
  146. Global menu_ship2
  147. Global menu_ship_hor
  148. Global menu_ship_ver#
  149. Global menu_ship_type
  150.  
  151. ;sounds (and related) variables
  152. Global sound_explosion1
  153. Global sound_explosion2
  154. Global sound_explosion_channel
  155. Global sound_icon
  156. Global sound_icon_channel
  157. Global sound_boosters
  158. Global sound_boosters_channel
  159. Global sound_enemy_laser
  160. Global sound_enemy_laser_channel
  161. Global sound_player_laser
  162. Global sound_player_laser_channel
  163. Global sound_hyperjump
  164. Global sound_hyperjump_channel
  165. Global sound_collision
  166. Global sound_collision_channel
  167. Global sound_cloak
  168. Global sound_cloak_channel
  169. Global sound_bullethit1
  170. Global sound_bullethit2
  171. Global sound_bullethit_channel
  172. Global music_menu
  173. Global music_menu_level#
  174. Global music_game
  175. Global music_game_level#
  176.  
  177. ;Types are like Structures in C. You have a "Type" called whatever. Then you can make multiple versions of the type. Each version of the Type has the same properties, i.e.:
  178. ;a FISH (the Type) has EYES, MOUTH, SCALES And FINS (it's properties) - ALL FISH have these properties.
  179. ;a DOG (the Type) has EYES, MOUTH, FUR and TAIL (it's properties) - ALL DOGS have these properties (look like this.)
  180. Type stars                        ;create "Type" for parallex stars
  181.     Field depth,x#,y#            ;each star has a depth, x and y position and a picture
  182. End Type
  183.  
  184. Type enemies                    ;same for enemies
  185.     Field x#,y#,energy,angle,speed#,style,maxspeed,dest_angle,dist_travelled,dist_to_go,dest_opp#,dest_hyp#,dest_adj#,rotate_angle,status,bulletlimiter,exp_frame#,gen
  186. End Type
  187. ;notice the "enemies" Type has a "style"?
  188. ;originally, I planned to have different styles of enemy space-ships, but never got around to drawing the graphics!
  189. ;the "style" is used in the subsequent code, and the Type property remains, so *technically* adding new enemy styles to the game should be pretty easy! :)
  190.  
  191. Type icons                        ;same for icons
  192.     Field x#,y#,style,frame#
  193. End Type
  194.  
  195. ;this is for the bullets. I've used an array, rather than a type (which would have been just as good in this case) to show you how MULTIDIMENSIONAL arrays can work.
  196. Const bulletnum = 500
  197. Global bulletlimiter
  198. Global nextbullet = 0
  199. Dim bullets(bulletnum-1,7) ;create an array for 'bulletnum' (0 to bulletnum -1) on-screen bullets with 8 values per bullet:
  200.                         ;0 = bullet_x, 1 = bullet_y, 2 = bullet_angle, 3 = bullet_speed,
  201.                         ;4 = bullet_style, 5 = bullet_animframe, 6 = bullet_origin_x, 7 = bullet_origin_y
  202.                         ;we'll say that a bullet's style can also say whether or not it's in use, i.e.: 0 = off, 1 = player, 2 = enemy1
  203.  
  204. ;load in the sounds (credit given for .WAV source)
  205. sound_icon = LoadSound("SndRes/icon.wav")                    ;Mark Rayson
  206. sound_enemy_laser = LoadSound("SndRes/enemy-laser.wav")        ;Mark Rayson
  207. sound_hyperjump = LoadSound("SndRes/hyperjump.wav")            ;Mark Rayson
  208. SoundPitch sound_hyperjump,32000    ;Mark's sample lasted a bit too long in it's original format (22000 Hz), so increasing the Pitch to 32000 Hz makes the sample play faster (and audibly higher too)
  209. sound_collision = LoadSound("SndRes/collision.wav")            ;Mark Rayson
  210. sound_explosion1 = LoadSound("SndRes/explosion1.wav")         ;WAV Central (www.wavcentral.com)
  211. sound_explosion2 = LoadSound("SndRes/explosion2.wav")         ;WAV Central (www.wavcentral.com)
  212. sound_boosters = LoadSound("SndRes/boosters.wav")            ;WAV Central (www.wavcentral.com)
  213. sound_player_laser = LoadSound("SndRes/player-laser.wav")    ;WAV Central (www.wavcentral.com)
  214. sound_cloak = LoadSound("SndRes/cloak.wav")                    ;WAV Central (www.wavcentral.com)
  215. sound_bullethit1 = LoadSound("SndRes/bullethit1.wav")        ;EarthStation1 (www.earthstation1.com)
  216. sound_bullethit2 = LoadSound("SndRes/bullethit2.wav")        ;EarthStation1 (www.earthstation1.com)
  217.  
  218.  
  219. ;This peice of code reads a file called "rift.dat" for the HI_SCORE and LAST_SCORE values from the last session
  220. SCORE_FILE = ReadFile("rift.dat")    ;use the variable SCORE_FILE (similar to image numbers before) as a reference to the file
  221.                                     ;open a file for READING ("ReadFile"). The file is called "Rift.dat"
  222. If SCORE_FILE = 0 Then                ;if the file wasn't found, then the reference "SCORE_FILE" will have been set to 0
  223.     HI_SCORE = 0
  224.     LAST_SCORE = 0
  225. Else                                ;if the file wasn't found, then the reference "SCORE_FILE" will have been set to something *other* than 0.
  226.     HI_SCORE = Int(ReadLine(SCORE_FILE))    ;read in one line from the file, then make it equal a number, rather than the ASCII string it is stored as. The first line becomes the HI_SCORE
  227.     LAST_SCORE = Int(ReadLine(SCORE_FILE))  ;read in another line from the file. This is the LAST_SCORE.
  228. End If
  229. CloseFile(SCORE_FILE)                ;we've finished with the file, so CLOSE it (tells Blitz to disregard the reference number) - we won't be READing from it anymore!
  230.  
  231. ;This section turns the Integer HI_SCORE and LAST_SCORE values into strings with leading 0's
  232. ;i.e.: 1000 becomes "0001000". You will see this exact same peice of code later on, so - professionally - it *should* have been done in a FUNCTION.
  233. ;I've kept it separate to show that you *can* just as well use copied code and not see a difference in the final program.
  234. If HI_SCORE < 10 Then                                    ;If the value of HI_SCORE is less than 10, then..
  235.     HI_SCORE_STR = "000000"+Str(HI_SCORE)                ;make the string "HI_SCORE_STR" = "000000" and put the value of HI_SCORE on the end as a string
  236.                                                         ;such that, for example, HI_SCORE_STR now holds the text: "0000003"
  237.                                                         
  238. ElseIf HI_SCORE >=10 And HI_SCORE < 100 Then            ;If the value of HI_SCORE is 10 or more, AND the value of HI_SCORE is less than 100, then..
  239.     HI_SCORE_STR = "00000"+Str(HI_SCORE)                ;.. and so on.. the use of "AND" here means that both 'arguements' (the HI_SCORE >= 10 type bits)
  240.                                                         ;must be true, or the resulting operation (the HI_SCORE_STR = ... type bit) won't happen.
  241.                                                         ;In this case, for example, 104 *is* "10 or more" but it *is not* less than 100, so ignore this "If statement"
  242.                                                         ;The "ElseIf" keyword means that if the first "IF" didn't fire, then "try this one"..
  243. ElseIf HI_SCORE >=100 And HI_SCORE < 1000 Then
  244.     HI_SCORE_STR = "0000"+Str(HI_SCORE)
  245. ElseIf HI_SCORE >=1000 And HI_SCORE < 10000 Then
  246.     HI_SCORE_STR = "000"+Str(HI_SCORE)
  247. ElseIf HI_SCORE >=10000 And HI_SCORE < 100000 Then
  248.     HI_SCORE_STR = "00"+Str(HI_SCORE)
  249. ElseIf HI_SCORE >=100000 And HI_SCORE < 1000000 Then
  250.     HI_SCORE_STR = "0"+Str(HI_SCORE)
  251. ElseIf HI_SCORE >=100000 And HI_SCORE < 10000000 Then
  252.     HI_SCORE_STR = Str(HI_SCORE)
  253. Else                                                    ;The "Else" keyword means that if NONE of the other IF statements fired, then do this next bit, as a last resort!
  254.                                                         ;The "Else" statement always comes last in an "IF.. ELSEIF.. ENDIF" peice of code
  255.     HI_SCORE_STR = "9999999"
  256. End If                                                    ;The "EndIf" keyword means that's the end of this set of checks.
  257.  
  258. If LAST_SCORE < 10 Then                                        ;Starting a new "IF.. ELSEIF.. ENDIF" peice of code, rather than using more "ElseIf"s means that this
  259.     LAST_SCORE_STR = "000000"+Str(LAST_SCORE)                ;set of decisions is not affected by the previous set.
  260. ElseIf LAST_SCORE >=10 And LAST_SCORE < 100 Then
  261.     LAST_SCORE_STR = "00000"+Str(LAST_SCORE)
  262. ElseIf LAST_SCORE >=100 And LAST_SCORE < 1000 Then
  263.     LAST_SCORE_STR = "0000"+Str(LAST_SCORE)
  264. ElseIf LAST_SCORE >=1000 And LAST_SCORE < 10000 Then
  265.     LAST_SCORE_STR = "000"+Str(LAST_SCORE)
  266. ElseIf LAST_SCORE >=10000 And LAST_SCORE < 100000 Then
  267.     LAST_SCORE_STR = "00"+Str(LAST_SCORE)
  268. ElseIf LAST_SCORE >=100000 And LAST_SCORE < 1000000 Then
  269.     LAST_SCORE_STR = "0"+Str(LAST_SCORE)
  270. ElseIf LAST_SCORE >=100000 And LAST_SCORE < 10000000 Then
  271.     LAST_SCORE_STR = Str(LAST_SCORE)
  272. Else
  273.     LAST_SCORE_STR = "9999999"
  274. End If
  275.  
  276. ;this code makes 4 'objects' in a "Type" called "ICONS".
  277. For i = 1 To 4                    ;do this 1, 2, 3, 4 times
  278.     icon.icons = New icons        ;create a new icon
  279.     icon\style = i                ;the icon style for each new icon is equal to the increment of i (i.e.: 1, 2, 3 or 4!)
  280.     icon\frame = Int(Rnd(0,5))    ;create a random frame number between 0 and 5 for each new icon
  281. Next
  282.  
  283. menustars = SCREEN_HEIGHT/3 ;generate a number of stars, so that they look dense enough on all test resolutions
  284. starson = 1 ;tells the program to show the stars (see later)
  285. For i=0 To menustars                    ;create <menustars> number of stars in the STARS type
  286.     star.stars=New stars                ;add a new star for each increment of i
  287. Next
  288.  
  289. For i = 1 To 10
  290.     enemy.enemies = New enemies ;make 10 enemies (we'll set their variables later)
  291. Next
  292.  
  293. ;this code loads the image numbers into an array called "game_ stars", which we DIMmed earlier. It has 6 containers (0,1,2,3,4,5) but I'm only using 1 to 5!
  294. ;an "image number" is what Blitz uses to reference graphics held in the Video Memory, i.e.:
  295. ;1. Image number 12 is a picture of a flower.
  296. ;2. Make a variable called "flower_pic" = 12
  297. ;3. Wherever Blitz is told to draw "flower_pic", reference image number 12 in the Video Memory.
  298. game_stars(1) = LoadImage("GfxRes/backg-star-1.bmp")    ;container (1) in "game_stars" holds the image number for this picture ("GfxRes/backg-star-1.bmp")
  299. game_stars(2) = LoadImage("GfxRes/backg-star-2.bmp")    ;etc..
  300. game_stars(3) = LoadImage("GfxRes/backg-star-3.bmp")
  301. game_stars(4) = LoadImage("GfxRes/backg-star-4.bmp")
  302. game_stars(5) = LoadImage("GfxRes/backg-star-5.bmp")
  303. For i = 1 To 5
  304.     MaskImage game_stars(i),255,0,255    ;mask the images for each star, so that MAGENTA (255,0,255) is the transparent colour
  305. Next
  306.  
  307. ;similarly, this code loads the image numbers into an array called "game_icons"
  308. ;however, these are images that contain the frames of an Animation, so a different Load command is used.
  309. game_icons(1) = LoadAnimImage("GfxRes/icon-boost.bmp",32,32,0,6)    ;LoadAnimImage has the same structure as LoadImage, with additional numbers after the picture filename
  310. game_icons(2) = LoadAnimImage("GfxRes/icon-shield.bmp",32,32,0,6)    ;these are: Frame Width (pixels), Frame Height (pixels), Starting Framenumber (usually 0)
  311. game_icons(3) = LoadAnimImage("GfxRes/icon-cloak.bmp",32,32,0,6)    ;and the Number of Frames in the Image (as *you* would count them (in this case 6)
  312. game_icons(4) = LoadAnimImage("GfxRes/icon-jump.bmp",32,32,0,6)        ;have a look at the file "icon-boost" in Paint Shop Pro and see for yourself the 6 frames of animation.
  313. For i = 1 To 4
  314.     MaskImage game_icons(i),255,0,255    ;mask the images for each icon, so that MAGENTA (255,0,255) is the transparent colour
  315. Next
  316.  
  317. game_jumps_level(1) = LoadImage("GfxRes/game-jumps-level1.bmp")
  318. game_jumps_level(2) = LoadImage("GfxRes/game-jumps-level2.bmp")
  319. game_jumps_level(3) = LoadImage("GfxRes/game-jumps-level3.bmp")
  320. game_jumps_level(4) = LoadImage("GfxRes/game-jumps-level4.bmp")
  321. game_jumps_level(5) = LoadImage("GfxRes/game-jumps-level5.bmp")
  322. For i = 1 To 5
  323.     MaskImage game_jumps_level(i),255,0,255    ;mask the images for each level block, so that MAGENTA (255,0,255) is the transparent colour
  324. Next
  325.  
  326. ;notice in the following code, we're loading (and MASKING) graphics in exactly the same way as before, but into regular variables instead of arrays.
  327. ;this next bit is all animations
  328. game_player = LoadAnimImage("GfxRes/player-ship.bmp",80,80,0,72) ;load in the 'sprite' for the player ship
  329. MaskImage game_player,255,0,255 ;mask the images for the player ship, so that MAGENTA (255,0,255) is the transparent colour
  330. game_enemy1 = LoadAnimImage("GfxRes/enemy1-ship.bmp",64,64,0,72) ;load in the 'sprite' for the enemy ship (type 1)
  331. MaskImage game_enemy1,255,0,255 ;mask the images for the enemy ship (type 1), so that MAGENTA (255,0,255) is the transparent colour
  332. game_bullet_player = LoadAnimImage("GfxRes/bullet-player.bmp",10,10,0,6)    ; the blue player bullet animation
  333. MaskImage game_bullet_player,255,0,255 ;mask the images
  334. game_bullet_enemy1 = LoadAnimImage("GfxRes/bullet-enemy1.bmp",10,10,0,6)    ; the orange enemy bullet animation
  335. MaskImage game_bullet_enemy1,255,0,255 ;mask the images
  336. game_explosion = LoadAnimImage("GfxRes/game-explosion.bmp",100,100,0,25)    ; the explosion, as done by Lennart's MkExpl 3.0
  337. MaskImage game_explosion,255,0,255 ;mask the images
  338. game_scorefont = LoadAnimImage("GfxRes/game-scorefont.bmp",18,14,0,11)        ; the score font used in the game
  339. MaskImage game_scorefont,255,0,255 ;mask the images
  340. menu_scorefont = LoadAnimImage("GfxRes/menu-scorefont.bmp",18,14,0,11)        ; the score font used on the menu
  341. MaskImage menu_scorefont,255,0,255 ;mask the images
  342. ;these are all plain single-frame pictures
  343. ;menu piccies
  344. menu_logo = LoadImage("GfxRes/menu-logo.bmp")            ;the CELESTIAL RIFT logo
  345. menu_ship1 = LoadImage("GfxRes/menu-ship1.bmp")            ;the big player-type ship
  346. menu_ship2 = LoadImage("GfxRes/menu-ship2.bmp")            ;the big enemy type ship
  347. menu_guildhall = LoadImage("GfxRes/menu-guildhall.bmp")    ;the GUILDHALL message at the top
  348. menu_thanks = LoadImage("GfxRes/menu-thanks.bmp")        ;the THANKS message at the bottom
  349. menu_credit = LoadImage("GfxRes/menu-credit.bmp")        ;the CREDITS message below the logo
  350. menu_start = LoadImage("GfxRes/menu-start.bmp")            ;the "PRESS FIRE TO START" caption
  351. menu_quit = LoadImage("GfxRes/menu-quit.bmp")            ;the "(ESCAPE TO QUIT)" caption
  352. menu_hiscore = LoadImage("GfxRes/menu-hiscore.bmp")        ;the "HI SCORE" caption
  353. menu_lastscore = LoadImage("GfxRes/menu-lastscore.bmp")    ;the "LAST SCORE" caption
  354. ;game piccies
  355. game_background = LoadImage("GfxRes/game-bg.bmp")             ;the sexy blue background behind the stars
  356. game_radar = LoadImage("GfxRes/game-radar.bmp")                ;the radar box
  357. game_shields = LoadImage("GfxRes/game-shields.bmp")            ;the shields box
  358. game_jumps = LoadImage("GfxRes/game-jumps.bmp")                ;the jumps box
  359. game_cloak = LoadImage("GfxRes/game-cloak.bmp")                ;the cloak box
  360. game_boosters = LoadImage("GfxRes/game-boosters.bmp")        ;go on.. guess.. it's the boosters box
  361. game_levels = LoadImage("GfxRes/game-levels.bmp")            ;this is the big RED-to-GREEN bar used on the cloak, shields and booster's boxes.
  362. game_score = LoadImage("GfxRes/game-score.bmp")                ;the score box
  363. game_hiscore = LoadImage("GfxRes/game-hiscore.bmp")            ;the hi score box
  364. game_gameover = LoadImage("GfxRes/game-gameover.bmp")        ;the game over logo, which I tend to see a lot of.. :(
  365. game_paused = LoadImage("GfxRes/game-paused.bmp")            ;the paused logo
  366. game_player_dot = LoadImage("GfxRes/player-radardot.bmp")    ;radar dots for the player, enemy and bonus icons respectively
  367. game_enemy1_dot = LoadImage("GfxRes/enemy1-radardot.bmp")
  368. game_icon_dot = LoadImage("GfxRes/icon-radardot.bmp")
  369. MaskImage menu_ship1,255,0,255            ;mask all the images.
  370. MaskImage menu_ship2,255,0,255            ;notice that it doesn't matter what order you do the masks in!
  371. MaskImage menu_credit,255,0,255
  372. MaskImage menu_guildhall,255,0,255        ;by the way, if when testing your program, you get the error message "IMAGE DOES NOT EXIST" at this point
  373. MaskImage menu_thanks,255,0,255            ;in the program, it's because the LOADIMAGE command above didn't find the file properly.
  374. MaskImage menu_start,255,0,255            ;This is usually either because; 1 - You've typed the wrong filename in the LOADIMAGE bit, or
  375. MaskImage menu_quit,255,0,255            ;2 - You've got the variable name wrong in the MASKIMAGE bit.
  376. MaskImage menu_hiscore,255,0,255
  377. MaskImage menu_lastscore,255,0,255        ;you could perform some checks at the end of loading all the images, so that you know they've all been loaded
  378. MaskImage game_radar,255,0,255            ;successfully. If they haven't then you could end the program properly and tell the user that they've got
  379. MaskImage game_shields,255,0,255        ;corrupt or missing files!
  380. MaskImage game_jumps,255,0,255
  381. MaskImage game_cloak,255,0,255            ;as you'll see, I haven't bothered! :)
  382. MaskImage game_boosters,255,0,255
  383. MaskImage game_score,255,0,255
  384. MaskImage game_hiscore,255,0,255
  385. MaskImage game_background,255,0,255
  386. MaskImage game_gameover,255,0,255
  387. MaskImage game_paused,255,0,255
  388. MaskImage game_levels,255,0,255
  389.  
  390. ;Right! That's it, we've set up *everything* we're going to need from outside the program.
  391. menu_loop() ;start the proper program loop by 'calling' the function called "menu_loop()" - which, conveniently, is just coming up!!!
  392.  
  393. ;this function keeps the menu loop going.. It starts playing tunes and sets a couple of variables. 
  394. ;Then it goes into a never ending loop which carries out a sequence of checks and function calls.
  395. Function menu_loop() ;Start of the Function whose name is "menu_loop()"
  396.     FLAG_MENUON = 1 ;tells the program that the menu is running, for use in the REPEAT..FOREVER statement in a sec..
  397.     music_menu = PlayMusic("SndRes/Danube.mid")    ;start playing the music file "Danube.mid" (found in the SndRes folder) on channel "music_menu"
  398.     menu_ship_hor = (SCREEN_WIDTH/2)-(ImageWidth(menu_ship1)/2) ;this sets the starting horizontal position of the big ship on the menu
  399.     menu_ship_ver = SCREEN_HEIGHT+1    ;this sets the vertical starting position of the big ship on the menu at one pixel off the bottom of the screen.
  400.                                     ;notice that images are (by default) handled from the TOP-LEFT pixel, so, horizontally, I offset the value
  401.                                     ;to the left, by half the width of the ship image.
  402.     menu_ship_type = 1                ;set up some initial values for these counters
  403.     menu_frame = 1                    
  404.     menu_start_stat = 0
  405.     menu_accept_quit = 0
  406.     
  407.     music_menu_level = 1    ;this value will be used to set the volume of the music track in a minute..
  408.     Repeat        ;a REPEAT.. FOREVER loop will carry out the code in between for as long as the program is running..
  409.         If FLAG_MENUON = 1 Then    ;If the FLAG_MENUON flag is set to 1 then "do" the following..
  410.             menu_loop_update()    ;call function "menu_loop_update()"
  411.             ;this IF statement checks to see if the game music is playing (as it will be when you quit the game)
  412.             If ChannelPlaying(music_game) = True Then        ;if it is, then..
  413.                 music_game_level = music_game_level -.01    ;decrease the value of this variable by .01
  414.                 ChannelVolume music_game, music_game_level    ;set the volume of this channel "music_game" to the value of music_game_level
  415.                 If music_game_level <= 0 Then                ;if the value of "music_game_level" is 0 or less, then
  416.                     StopChannel(music_game)                    ;stop the sounds playing on channel "music_game"
  417.                 End If                                        ;notice I've used an IF statement inside of another IF statement.. You'll be doing this a lot, it's called "Nesting"
  418.             End If
  419.         Else                                    ;if the FLAG_MENUON flag wasn't set to 1 then "do" the following..
  420.             SCORE_FILE = WriteFile("rift.dat")        ;Open file "rift.dat" for WRITing (using the variable "SCORE_FILE" as a reference number
  421.             WriteLine SCORE_FILE,Str(HI_SCORE)        ;Write the value of HI_SCORE (as a STRing) into the file
  422.             WriteLine SCORE_FILE,Str(LAST_SCORE)    ;Write the value of LAST_SCORE (as a STRing) into the file
  423.             CloseFile(SCORE_FILE)                    ;Close the file, as we've finished with it
  424.             End                                        ;END the program
  425.         End If
  426.         If ChannelPlaying(music_menu) = False Then            ;checks to see if the menu music has finished playing on channel "music_menu", if so, restart it!
  427.             music_menu = PlayMusic("SndRes/Danube.mid")
  428.         End If
  429.     Forever    ;end of the REPEAT.. FOREVER loop
  430. End Function ;End of the function
  431.  
  432. ;"menu_loop_update()" checks for key-presses, alters position coordinates on the screen
  433. ;and various variables/flags for use in "menu_draw_update()" and the game functions too.
  434. ;in fact, you'll see that this has the same organisational structure as the proper game loop (albeit much less complex!)
  435. Function menu_loop_update()
  436.     frames = WaitTimer(timer) ;returns a value to "frames" for how many video screen refreshes (The MHz of your monitor) occured since the last call to our timer
  437.     For i = 1 To frames    ;update the screen positions for "frames" number of changes.. This enables drawing frames to be skipped on slower machines.
  438.         If KeyDown(KEY_QUIT)                ;If the user presses the "QUIT" button on the keyboard, then..
  439.             FlushKeys                        ;(when using SCAN CODES, flush the keyboard buffer after each successful "Have they pressed a particular key" question.)
  440.  
  441.             If menu_accept_quit = 1 Then    ;If the variable "menu_accept_quit" is 1, then set the FLAG_MENUON to 0.
  442.                 FLAG_MENUON = 0                ;back in the "menu_loop()" function, this will cause the program to end!
  443.             End If
  444.         End If
  445.  
  446.         If KeyDown(KEY_FIRE)                ;If the user presses the "FIRE" button on the keyboard, then..
  447.             FlushKeys
  448.             FLAG_DEBUG = 0                    
  449.             FLAG_GAMESTARTER = 1
  450.             hypercount = 102
  451.             FLAG_PAUSE = 0
  452.             game_loop()                            ;call the function called "game_loop()" (the game will run, but once it has ended, we'll find ourselves back here...)
  453.             
  454.             menu_ship_ver = SCREEN_HEIGHT+1
  455.             menu_frame = 1
  456.             menu_start_stat = 0
  457.             menu_accept_quit = 0                ;by setting this to 0, we'll stop the program ending by any surplus "QUIT" keystrokes carrying over from the game, by
  458.                                                 ;using the menu_frame counter at the end of this FOR loop.
  459.             FLAG_PAUSE = 0
  460.             If PLAYER_SCORE > HI_SCORE Then        ;checks to see if the PLAYER_SCORE from the last game is higher than the currently held "HI SCORE", if it is, then
  461.                 HI_SCORE = PLAYER_SCORE            ;that PLAYER_SCORE becomes the new HI SCORE!
  462.             End If
  463.             LAST_SCORE = PLAYER_SCORE            ;the LAST SCORE is always set to the PLAYER SCORE from the last game! :)
  464.             FlushKeys
  465.         End If
  466.         If KeyDown(KEY_DEBUG)                ;if the user presses the "DEBUG" button on the keyboard, then..
  467.             FlushKeys
  468.             FLAG_DEBUG = 1                        ;this is all exactly the same as "FIRE" above, but now FLAG_DEBUG is set to 1.
  469.             FLAG_GAMESTARTER = 1                ;later on, you'll see that we use this to turn on, or off, some overlayed displays in the game loop!
  470.             hypercount = 102
  471.             FLAG_PAUSE = 0
  472.             game_loop()
  473.             menu_ship_ver = SCREEN_HEIGHT+1
  474.             menu_frame = 1
  475.             menu_start_stat = 0
  476.             menu_accept_quit = 0
  477.             FLAG_PAUSE = 0
  478.             If PLAYER_SCORE > HI_SCORE Then
  479.                 HI_SCORE = PLAYER_SCORE    
  480.             End If
  481.             LAST_SCORE = PLAYER_SCORE    
  482.             FlushKeys
  483.         End If            
  484.         If KeyDown(KEY_SAVESCREEN)            ;if the user presses the "SAVESCREEN" button on the keyboard, then..
  485.             FlushKeys
  486.             FLAG_SAVESCREEN = 1                    ;just sets FLAG_SAVESCREEN to 1. You'll see this used in the next function.
  487.         End If
  488.         If menu_ship_ver > (-50 - ImageHeight(menu_ship1)) ;if the bottom of the (largest) ship picture gets to 50 pixels above the top of the screen
  489.             Select menu_ship_type    ;A SELECT..CASE statement is like an IF statement, but only performs 1 check, i.e.: "What is the value of I?"
  490.                 Case 1    ;if "menu_ship_type" is 1 then..
  491.                     menu_ship_ver = menu_ship_ver - .3 ;how fast menuship1 moves up the screen
  492.                 Case 2    ;if "menu_ship_type" is 1 then..
  493.                     menu_ship_ver = menu_ship_ver - .8 ;how fast menuship2 moves up the screen
  494.             End Select
  495.         Else
  496.             menu_ship_ver = SCREEN_HEIGHT+1    ;reset the vertical position so that the top of the ship is at the bottom of the screen
  497.             menu_ship_hor = Rnd(0,SCREEN_WIDTH-ImageWidth(menu_ship1)) ;create a random horizontal position
  498.             menu_ship_type = Int(Rnd(1,2)) ;randomly choose between values 1 or 2
  499.         End If
  500.         menu_frame = menu_frame + 1        ;increase the value of "menu_frame" by 1
  501.         If menu_frame = 25 Then            ;if the value of "menu_frame" gets to 25 then reset it to 1
  502.             menu_frame = 1
  503.             menu_accept_quit = 1            ;now we've turned the user's ability to press the "QUIT" button back on (see the IF statement in the KeyDown(KEY_QUIT) statement above!
  504.             If menu_start_stat = 1 Then    ;this bit just switches the value of "menu_start_stat" between 1 and 0, i.e. :If it's 1, then make it 0, if it's 0, then make it 1 etc.
  505.                 menu_start_stat = 0        ;this will be used in the next function to flash the "PRESS FIRE TO START" caption on and off!
  506.             Else
  507.                 menu_start_stat = 1
  508.             End If
  509.         End If
  510.     Next
  511.     If HI_SCORE < 10 Then                                        ;remember this from before? I was saying it could've been done in a function?
  512.         HI_SCORE_STR = "000000"+Str(HI_SCORE)                    ;exactly the same code.. (just converts the number 103 to the string "0000103")
  513.     ElseIf HI_SCORE >=10 And HI_SCORE < 100 Then
  514.         HI_SCORE_STR = "00000"+Str(HI_SCORE)
  515.     ElseIf HI_SCORE >=100 And HI_SCORE < 1000 Then
  516.         HI_SCORE_STR = "0000"+Str(HI_SCORE)
  517.     ElseIf HI_SCORE >=1000 And HI_SCORE < 10000 Then
  518.         HI_SCORE_STR = "000"+Str(HI_SCORE)
  519.     ElseIf HI_SCORE >=10000 And HI_SCORE < 100000 Then
  520.         HI_SCORE_STR = "00"+Str(HI_SCORE)
  521.     ElseIf HI_SCORE >=100000 And HI_SCORE < 1000000 Then
  522.         HI_SCORE_STR = "0"+Str(HI_SCORE)
  523.     ElseIf HI_SCORE >=100000 And HI_SCORE < 10000000 Then
  524.         HI_SCORE_STR = Str(HI_SCORE)
  525.     Else
  526.         HI_SCORE_STR = "9999999"
  527.     End If
  528.     If LAST_SCORE < 10 Then
  529.         LAST_SCORE_STR = "000000"+Str(LAST_SCORE)
  530.     ElseIf LAST_SCORE >=10 And LAST_SCORE < 100 Then
  531.         LAST_SCORE_STR = "00000"+Str(LAST_SCORE)
  532.     ElseIf LAST_SCORE >=100 And LAST_SCORE < 1000 Then
  533.         LAST_SCORE_STR = "0000"+Str(LAST_SCORE)
  534.     ElseIf LAST_SCORE >=1000 And LAST_SCORE < 10000 Then
  535.         LAST_SCORE_STR = "000"+Str(LAST_SCORE)
  536.     ElseIf LAST_SCORE >=10000 And LAST_SCORE < 100000 Then
  537.         LAST_SCORE_STR = "00"+Str(LAST_SCORE)
  538.     ElseIf LAST_SCORE >=100000 And LAST_SCORE < 1000000 Then
  539.         LAST_SCORE_STR = "0"+Str(LAST_SCORE)
  540.     ElseIf LAST_SCORE >=100000 And LAST_SCORE < 10000000 Then
  541.         LAST_SCORE_STR = Str(LAST_SCORE)
  542.     Else
  543.         LAST_SCORE_STR = "9999999"
  544.     End If
  545.     menu_draw_update() ;call the function "menu_draw_update" which draws all these new things on the screen
  546. End Function
  547.  
  548. ;"menu_draw_update()" just draws things on your monitor, using values set and altered in the last function (menu_loop_update).
  549. Function menu_draw_update()
  550.     SetBuffer BackBuffer()    ;draw all of the following to the backbuffer() which is an area video memory which is not shown on screen.
  551.                             ;the idea is that you draw everything here, then SHOW it to the user when the full picture is complete.
  552.                             
  553.     ClsColor 0,0,0        ;changes the CLearScreen colour to black (0,0,0)
  554.                         ;Color commands use the 3 parameters as RED value, GREEN value, BLUE value
  555.                         ;which is how pixel colours are made up on the monitor. If you're familiar with
  556.                         ;any PC Paint Packages, you'll probably be quite familiar with this.
  557.     Cls                    ;CLears the Screen
  558.     
  559.     ;this next section draws all of the pictures on to the backbuffer() at the specified coordinates.
  560.     ;notice that the pictures are drawn in sequence, with the backmost things drawn first and the foremost things drawn last
  561.     ;kind of like making a collage!
  562.     DrawImage menu_logo,(SCREEN_WIDTH/2)-(ImageWidth(menu_logo)/2),0    ;this draws the menu_logo image at "x","y"
  563.                         ;I've used EQUATIONS to make up x and y for all the images in this project, so that when you change
  564.                         ;the resolution values (back at the beginning of the code) everything still appears at the correct position
  565.                         ;on the screen. If you know what resolution you'll be working at, then you can quite happily put x and y as
  566.                         ;ordinary numbers in here.
  567.                         ;For example, at 800*600, the menu_logo image will be drawn at:
  568.                         ;SCREEN_WIDTH = 800
  569.                         ;800/2 = 400
  570.                         ;ImageWidth(menu_logo) is the width (in pixels) of this particular image (which is 547 pixels)
  571.                         ;547/2 = 273.5
  572.                         ;(800 - 273.5 = 126.5)
  573.                         ;So, menu_logo would be drawn at 127,0 (because Blitz requires whole number coordinates, it will automatically
  574.                         ;round up 126.5 to be 127.)
  575.     DrawImage menu_guildhall,(SCREEN_WIDTH/2)-(ImageWidth(menu_guildhall)/2),5
  576.     DrawImage menu_credit,(SCREEN_WIDTH/2)-(ImageWidth(menu_credit)/2),200
  577.     DrawImage menu_quit,(SCREEN_WIDTH/2)-(ImageWidth(menu_quit)/2),SCREEN_HEIGHT-75
  578.     DrawImage menu_hiscore,10,SCREEN_HEIGHT-45
  579.     DrawImage menu_lastscore,(SCREEN_WIDTH)-282,SCREEN_HEIGHT-45
  580.  
  581.     ;this next bit builds each number in the HI_SCORE_STR and LAST_SCORE_STR out of the pictures in the score font
  582.     For i = 1 To 7    ;there are 7 numbers in the STRING.
  583.         DrawImage menu_scorefont,100+((i-1)*24),SCREEN_HEIGHT-44,Int(Mid(HI_SCORE_STR,i,1))
  584.                 ;let's break this up.. firstly "100+((i-1)*24"
  585.                 ;the leftmost number in the string first (i = 1)
  586.                 ;x position = 100+((i-1)*24
  587.                 ;=100+((0)*24)
  588.                 ;=100+(0)
  589.                 ;=100
  590.                 ;the next number in the string (i = 2)
  591.                 ;x position = 100+((i-1)*24
  592.                 ;=100+((1)*24)
  593.                 ;=100+(24)
  594.                 ;=124
  595.                 ;the next number in the string (i = 3)
  596.                 ;x position = 100+((i-1)*24
  597.                 ;=100+((2)*24)
  598.                 ;=100+(48)
  599.                 ;=148
  600.                 ;etc... this offsets each number in the seven digit long number across the screen!
  601.                 
  602.                 ;Okay.. Now the "Int(Mid(HI_SCORE_STR,i,1))" bit..
  603.                 ;"Mid(HI_SCORE_STR,i,1)" takes one character, starting at "i" from the string "HI_SCORE_STR".
  604.                 ;For example, if i=4 and HI_SCORE_STR = "0023560" then
  605.                 ;"Mid(HI_SCORE_STR,i,1)" would give us "3".
  606.                 ;the "INT" bit turns the ASCII string value "3" into an integer number 3.
  607.  
  608.                 ;Finally, the "Int(Mid(HI_SCORE_STR,i,1))" bit is the frame number in an Animation Image (remember LoadAnimImage before?)
  609.                 ;Although the "menu_score_font" picture isn't technically an animation, this is a clever alternate use for AnimImages, where you can
  610.                 ;simply calculate which image to show, by it's "frame" position within the animation.
  611.                 ;if you check the file "menu-scorefont.bmp" in Paint Shop Pro, you'll see that the 3rd image from the left is, in fact, a pictorial number 3.
  612.         DrawImage menu_scorefont,(SCREEN_WIDTH)-167+((i-1)*24),SCREEN_HEIGHT-44,Int(Mid(LAST_SCORE_STR,i,1))
  613.                 ;exactly the same thing, but using LAST_SCORE_STR instead of HI_SCORE_STR!
  614.     Next
  615.     DrawImage menu_thanks,(SCREEN_WIDTH/2)-(ImageWidth(menu_thanks)/2),SCREEN_HEIGHT-15
  616.  
  617.     ;depending on the value set earlier in "menu_loop_update()" this draws one of the two ships at the relevant coordinates on-screen
  618.     ;menu_ship_hor is the x position, and is set once per "scroll up the screen" in menu_loop_update().
  619.     ;menu_ship_ver is the y position, which is repeatedly changed in menu_loop_update() to scroll the ships up the screen!
  620.     Select menu_ship_type
  621.         Case 1
  622.             DrawImage menu_ship1,menu_ship_hor,menu_ship_ver
  623.         Case 2
  624.             DrawImage menu_ship2,menu_ship_hor,menu_ship_ver
  625.     End Select
  626.     
  627.     ;Remember before, I was saying that "menu_frame" would be used to flash the "START GAME" caption on and off?
  628.     ;when "menu_frame" got to 25, the variable "menu_start_stat" was flipped between 1 or 0
  629.     If menu_start_stat = 1 Then
  630.         ;if the variable "menu_start_stat" = 1 then draw the caption. If it isn't, ignore drawing the caption.
  631.         ;On and off, on and off. Simple as that! This technique will be used again later for the PAUSE and GAME_OVER captions!
  632.         DrawImage menu_start,(SCREEN_WIDTH/2)-(ImageWidth(menu_start)/2),(SCREEN_HEIGHT/2)+(ImageHeight(menu_start)*4)
  633.     End If
  634.  
  635.     ;Remember when we checked to see if the user had pressed the "SAVESCREEN" button, earlier?
  636.     ;if they did, we set FLAG_SAVESCREEN to 1. Now this is where that takes effect..
  637.     If FLAG_SAVESCREEN=1 Then
  638.         SaveBuffer (BackBuffer(),"CRMenuScreen.bmp")
  639.             ;the SaveBuffer command outputs the contents of the named buffer (in this case "BackBuffer()") to the named file, in a BMP format.
  640.         FLAG_SAVESCREEN = 0
  641.             ;after we've saved the screen, we reset the FLAG to 0, so that when we come back for the next "menu_draw_update", it won't save
  642.             ;another picture. (i.e.: it only saves 1 picture for each keypress of the "SAVESCREEN" button!)
  643.             ;This is useful for getting working screenshots of your project to impress your mates!! :)
  644.     End If 
  645.     Flip    ;finally, FLIP everything on the backbuffer() and show it on the frontbuffer(), i.e.: your monitor!!
  646. End Function
  647.  
  648. ;this function keeps the game loop going.. It starts playing tunes and sets a couple of variables. 
  649. ;Then it goes into a never ending loop which carries out a sequence of checks and function calls, until such time as we want to stop it!
  650. Function game_loop()
  651.     FLAG_GAMEON = 1 ;tells the program that the game is running.
  652.     game_initialise()     ;calls a function called "game_initialise()" (which is next in the code) which
  653.                         ;just gives the player full energy and a score of 0 etc..)
  654.     music_game_level = 0.3    ;the XM tune I've used is an old Amiga Module from a game called Dynablaster
  655.                             ;it's a bit loud to go with the game, though, so I want it's volume to be lower than
  656.                             ;normal.. see in a second..
  657.     music_game = PlayMusic("SndRes/Dynablaster.xm")    
  658.     ChannelVolume music_game, music_game_level    ;remembering that we want to play it quieter, so set it's CHANNELVOLUME to music_game_level (as set a second ago!)
  659.  
  660.     sound_hyperjump_channel = PlaySound(sound_hyperjump)     ;The game starts in what seems to be mid-hyperjump, but because
  661.                                                             ;this sound is normally called after a keypress, I've got to do it manually
  662.                                                             ;just this once! ;)
  663.     Repeat        ;as with the menu, we want to cycle though the process of updating/drawing forever, until such time as the game has ended.
  664.         If FLAG_GAMEON = 1 Then        ;.. so, if FLAG_GAMEON is 1, then "do" the following.
  665.             game_loop_update()                                ;call the game_loop_update() function
  666.             If ChannelPlaying(music_menu) = True Then        ;this bit slowly turns down the menu music, until the music_menu_level is 0..
  667.                 music_menu_level = music_menu_level -.01    
  668.                 ChannelVolume music_menu, music_menu_level
  669.                 If music_menu_level <= 0 Then                ;.. then turns it off completely!
  670.                     StopChannel(music_menu)
  671.                 End If
  672.             End If
  673.         Else
  674.             FlushKeys                ;if FLAG_GAMEON isn't 1, then instead of ENDing the program (as we did from the menu), this time
  675.             Exit                    ;we EXIT the function, which effectively takes us back to the line after "game_loop()" was originally
  676.                                     ;called, back in "menu_loop_update()"
  677.         End If
  678.         If ChannelPlaying(music_game) = False Then        ;once again, this checks if the game music has finished playing
  679.             music_game = PlayMusic("SndRes/Dynablaster.xm")    ;and starts it again..
  680.             ChannelVolume music_game, music_game_level    ;remembering that we want to play it quieter, so set it's CHANNELVOLUME to music_game_level (as set a second ago!)
  681.         End If
  682.     Forever
  683. End Function
  684.  
  685. ;As described a minute ago, this function sets up the game variables as they should be
  686. ;at the start of every game, i.e.: Player Shields are full, the score is 0 etc..
  687. Function game_initialise()
  688.     PLAYER_SCORE = 0
  689.     PLAYER_TIME = 0
  690.     PLAYER_ANGLE = 0
  691.     PLAYER_SPEED = 0
  692.     PLAYER_SHIELD = 192            ;the width of the game_level image is 192. Rather than working out a percentage of 100, it's much
  693.     PLAYER_BOOSTERS = 192        ;easier to use the width of the image on such BAR type displays.
  694.     PLAYER_CLOAK = 192            
  695.     PLAYER_JUMPS = 5
  696.     gameovercounter = 0
  697.     player_explosion_frame = 0
  698.     game_player_randomize()            ;calls a function that randomizes a player's position on the map
  699.     game_stars_randomize()            ;calls a function that randomizes the star positions
  700.  
  701.     ;this next bit is the first time you'll have seen a TYPE cycle.
  702.     ;Just like a normal "For i = 0 to 20" loop, this goes through each Version of a type
  703.     ;and set's it's properties. (i.e.: That FISH type has a SCALES property. Here we tell it that this particular Fish's Scales are GOLD!)
  704.     For enemy.enemies=Each enemies
  705.         enemy\x=Rnd(0,GAME_AREA_X)        ;randomizes each "enemies"'s position on the map!
  706.         enemy\y=Rnd(0,GAME_AREA_Y)
  707.         enemy\energy = 100                    ;gives each "enemies" a full shield strength of 100
  708.         enemy\angle = Int(Rnd(0,72)) * 5    ;gives each "enemies" a random angle between 0 and 360, at increments of 5 degrees
  709.         enemy\maxspeed = Rnd(20,40)            ;gives each "enemies" a random maximum speed between 20 and 40 (a bit slower, and a bit faster than the player's
  710.                                             ;maximum speed (as originally coded by me. If you change the player's maximum speed, it will have no effect on 'them'!)
  711.         enemy\speed = 0
  712.         enemy\style = 1                        ;sets the "enemies"'s style to 1. Remember before when I said it would be easily possible to implement new styles of enemy?
  713.                                             ;well, this would be your starting point! :)
  714.                                             
  715.         enemy\exp_frame = 0                    ;like the player, an "enemies" has an explosion frame which is always zero(0) until it is ready to explode!
  716.                                             ;see later for the code which fire's an "enemies"'s final demise.
  717.  
  718.         enemy\dist_to_go = Rnd(ENEMY_MIN_DIST,ENEMY_MAX_DIST)    ;The "enemies"'s distance to go defines how far it will fly on it's current course, before it
  719.                                                                 ;retargets and turns towards you. This is a fairly simple, but reasonably effective enemy A.I.
  720.         enemy\dist_travelled = 0            ;directly related to the "enemies"'s distance to go, is how far it has travelled up to now.
  721.  
  722.         enemy\gen = 1            ;a last minute addition, when an enemy dies and regenerates, it is worth more points to kill next time around, thanks to its GEN number.
  723.     Next
  724.     
  725.     For icon.icons = Each icons
  726.         icon\x = Rnd(0,GAME_AREA_X)        ;for each of the 4 icons on the play area at any one point, we need a random x and y position.
  727.         icon\y = Rnd(0,GAME_AREA_Y)
  728.     Next
  729. End Function
  730.  
  731. ;once again, like it's menu equivalent, "game_loop_update()" is a function which analyses player input, working out all the new
  732. ;coordinate positions and anything else which needs deciding before updating the screen display.
  733. Function game_loop_update()
  734.     frames = WaitTimer(timer)
  735.     For i = 1 To frames
  736.         If KeyDown(KEY_PAUSE)                                    ;checks to see if the user has pressed the "PAUSE" key
  737.             FlushKeys
  738.             If game_accept_pause = 1 And gameovercounter = 0    ;the "game_accept_pause" variable is used in the same way as "menu_accept_quit" earlier.
  739.                                                                 ;because we're using SCANCODES, the program will register a number of qualifying cases where
  740.                                                                 ;when this check is performed, the key is still held down (at 50 frames per second, if the user
  741.                                                                 ;held down the key for half a second, the KEYDOWN function would fire around 25 times!)
  742.                                                                 ;A check is made on the value of "game_over_counter" to see if the player has died - in which
  743.                                                                 ;case Pausing the game is not allowed.
  744.                                                                 
  745.                 If FLAG_PAUSE = 0 Then                            ;If FLAG_PAUSE is 0 then..
  746.                     FLAG_PAUSE = 1                                ;make FLAG_PAUSE = 1
  747.                     game_accept_pause = 0                        ;don't accept any more "PAUSE" button presses until "game_accept_pause" is set back to 1
  748.                     game_pause_frame = 1                        ;make "game_pause_frame" = 1 which, similarly to "menu_frame" earlier will enable the flashing of "PAUSED".
  749.                 Else
  750.                     FLAG_PAUSE = 0                                ;If FLAG_PAUSE isn't 0 (the game was paused) then..
  751.                     game_accept_pause = 0                        ;do exactly the same, but set FLAG_PAUSE to 0.
  752.                     game_pause_frame = 1
  753.                 End If
  754.             End If
  755.         End If
  756.         If KeyDown(KEY_SAVESCREEN)        ;If the "SCREENSAVE" button is pressed..
  757.             FlushKeys                    ;this functions exactly the same as in menu_loop_update()
  758.             FLAG_SAVESCREEN = 1
  759.         End If
  760.         If KeyDown(KEY_QUIT)        ;If the "QUIT" button is pressed..
  761.             FlushKeys
  762.             hypercount = 0
  763.             cloakon = 0
  764.             FLAG_GAMEON=0             ;set FLAG_GAMEON to equal 0. Back in the "game_loop()" function, this will cause the code to jump back to the menu.
  765.         End If
  766.  
  767.         If FLAG_PAUSE = 0 Then                            ;this is really easy! If the game is paused then *don't* do any of the following code. No values will change,
  768.                                                         ;hence nothing will move on the screen when it comes to updating it later! :)
  769.                                                         
  770.             If gameovercounter = 0 Then                    ;if the game is still in progress, i.e.: "gameovercounter" = 0 (the player is still alive) then
  771.                                                         ;check for the following keypresses from the user - otherwise there's no point!
  772.                                                         
  773.                 If KeyDown(KEY_HYPER)                    ;if the "HYPER" key is pressed then..
  774.                     If PLAYER_JUMPS > 0 Then
  775.                         If hypercount = 0 Then                ;(if "hypercount" is 0, then we're not already in the middle of a HyperJump, so let's set things off!)
  776.                             hypercount = 1                        ;by setting "hypercount" to 1, we'll set off a chain of events later on..
  777.                             sound_hyperjump_channel = PlaySound(sound_hyperjump)        ;play the Hyperjump soundeffect on the appropriate channel reference
  778.                             PLAYER_JUMPS = PLAYER_JUMPS - 1        ;subtract the number of Jumps a player has left by 1
  779.                             If PLAYER_JUMPS <= 0 Then            ;if the number of jumps left is 0 or less, then the above subtraction will make it "-1", so..
  780.                                 PLAYER_JUMPS = 0                ;put it back to 0.
  781.                             End If
  782.                         End If
  783.                     End If
  784.                     FlushKeys
  785.                 End If
  786.                 If hypercount = 0 Then                        ;as long as we're not in the middle of a hyperjump, do the following..
  787.                 
  788.                     If KeyDown(KEY_CLOAK)            ;if the CLOAK key is pressed then
  789.                     
  790.                         If PLAYER_CLOAK > 2 Then        ;if the player has enough (2 points of) PLAYER_CLOAK left, then..
  791.                             cloakon = cloakon + 1                                    ;the cloakon value is incremented so that later on, we can do the flickering effect
  792.                             PLAYER_CLOAK = PLAYER_CLOAK - INCR_CLOAK_DOWN            ;subtract some PLAYER_CLOAK ability at a rate of "INCR_CLOAK_DOWN"
  793.                             
  794.                             If ChannelPlaying(sound_cloak_channel) = False Then        ;because the sound effect is triggered by a KeyDown event, it will fire repeatedly,
  795.                                 sound_cloak_channel = PlaySound(sound_cloak)        ;which makes an almighty noise as the echo of the sound effect builds on top of 
  796.                             End If                                                    ;eachother! By using this "If it's playing then do nothing, otherwise Play it again"
  797.                                                                                     ;peice of code, the sample plays once, then if the key is still held down, then it'll
  798.                                                                                     ;play it another once.. and so on.. (Take out the IF and the END IF to see what I mean!)
  799.                         Else                            ;if the player doesn't have enough PLAYER_CLOAK left then
  800.                             cloakon = 0                        ;reset the "cloakon" value to 0
  801.                             PLAYER_CLOAK = 0                ;Keep the PLAYER_CLOAK value at 0, so that it doesn't build up...
  802.                         End If
  803.                         FlushKeys
  804.                     Else                            ;if the CLOAK key isn't pressed then
  805.                         cloakon = 0                            ;reset the "cloakon" value to 0
  806.                         If PLAYER_CLOAK < 192                                ;if the player has less than the top value (192 points) of PLAYER_CLOAK then..
  807.                             PLAYER_CLOAK = PLAYER_CLOAK + INCR_CLOAK_UP            ;Slowly build up the PLAYER_CLOAK value.
  808.                         Else
  809.                             PLAYER_CLOAK = 192                                ;otherwise cap the PLAYER_CLOAK value at 192 points.
  810.                         End If
  811.                         FlushKeys
  812.                     End If
  813.                     If KeyDown(KEY_BOOST)                            ;the BOOST key works in exactly the same way as the CLOAK key
  814.                         If PLAYER_BOOSTERS > 2 Then
  815.                             If PLAYER_SPEED < (SPEED_MAX*3) Then
  816.                                 PLAYER_SPEED = PLAYER_SPEED + (INCR_SPEED * 3)
  817.                             End If
  818.                             If ChannelPlaying(sound_boosters_channel) = False Then
  819.                                 sound_boosters_channel = PlaySound(sound_boosters)
  820.                             End If
  821.                             PLAYER_BOOSTERS = PLAYER_BOOSTERS - INCR_BOOSTERS_DOWN
  822.                         Else
  823.                             PLAYER_BOOSTERS = 0
  824.                         End If
  825.                         FlushKeys
  826.                     Else
  827.                         If PLAYER_BOOSTERS < 192
  828.                             PLAYER_BOOSTERS = PLAYER_BOOSTERS + INCR_BOOSTERS_UP
  829.                         Else
  830.                             PLAYER_BOOSTERS = 192
  831.                         End If
  832.                         FlushKeys
  833.                     End If
  834.                     If KeyDown(KEY_FIRE) Then                    ;if the "FIRE" key is pressed, then..
  835.                         If bulletlimiter = 0 Then                    ;the "bulletlimiter" value works in exactly the same way as "game_accept_pause" earlier
  836.                                                                     ;in that we don't want too many bullets spraying out of the player, due to SCANCODE/framerate issues
  837.                             bulletlimiter = 1                        ;so we set the "bulletlimiter value to 1, so that until we say so (a bit later) no more "FIRE" keypresses
  838.                                                                     ;will trigger.
  839.                                                                     
  840.                             createbullet(PLAYER_X,PLAYER_Y,PLAYER_ANGLE,PLAYER_SPEED,1)        ;however, assuming we've got a successful "FIRE" event, let's create some bullets
  841.                                                                                             ;on the screen by calling the "createbullet()" function.. This is pretty cool, so
  842.                                                                                             ;see the function itself later on for explainations!
  843.                                                                                             
  844.                             sound_player_laser_channel = PlaySound(sound_player_laser)    ;play the appropriate sound effect on it's channel
  845.                         End If
  846.                         FlushKeys
  847.                     End If
  848.                     If KeyDown(KEY_CLOCKWISE)                            ;if "CLOCKWISE" key is pressed then..
  849.                         PLAYER_ANGLE = PLAYER_ANGLE + INCR_ROTATE            ;Add "INCR_ROTATE" degrees to the current PLAYER_ANGLE
  850.                         FlushKeys
  851.                         If PLAYER_ANGLE >= 360 Then                            ;if the PLAYER_ANGLE is 360, then reset it to 0.
  852.                             PLAYER_ANGLE = PLAYER_ANGLE - 360
  853.                         End If
  854.                     End If
  855.                     If KeyDown(KEY_ANTICWISE)                            ;exactly the same, but Subtract "INCR_ROTATE" from the player angle and
  856.                         PLAYER_ANGLE = PLAYER_ANGLE - INCR_ROTATE        ;reset it to (for example) 355, if the angle is -5.
  857.                         FlushKeys
  858.                         If PLAYER_ANGLE < 0 Then
  859.                             PLAYER_ANGLE = PLAYER_ANGLE + 360
  860.                         End If
  861.                     End If
  862.                     If KeyDown(KEY_SPEEDUP) Then                        ;if the "SPEEDUP" key is pressed.
  863.                         If PLAYER_SPEED < SPEED_MAX                            ;as long as the player speed is less than the maximum speed (SPEED_MAX), then
  864.                             PLAYER_SPEED = PLAYER_SPEED + INCR_SPEED        ;Add "INCR_SPEED" to the player's speed value
  865.                             FlushKeys
  866.                         Else
  867.                             PLAYER_SPEED = PLAYER_SPEED - INCR_SLOW            ;if the PLAYER_SPEED is not less than the maximum speed then take "INCR_SLOW" off of it!
  868.                             FlushKeys
  869.                         End If
  870.                     Else                                                ;if the key isn't being pressed, then..
  871.                         If PLAYER_SPEED > 0 Then                            ;as long as the player speed is greater than 0, then take "INCR_SLOW" off the current value
  872.                             PLAYER_SPEED = PLAYER_SPEED - INCR_SLOW            ;(this is an easy "No power" decelaration for the space ship)
  873.                         End If
  874.                         FlushKeys
  875.                     End If
  876.                     If KeyDown(KEY_SPEEDDOWN)                            ;exactly the same thing, but with the ship's thrusters in reverse! :)
  877.                         If PLAYER_SPEED > SPEED_MIN
  878.                             PLAYER_SPEED = PLAYER_SPEED - INCR_SPEED
  879.                             FlushKeys
  880.                         Else
  881.                             PLAYER_SPEED = SPEED_MIN
  882.                             FlushKeys
  883.                         End If
  884.                     Else
  885.                         If PLAYER_SPEED < 0 Then
  886.                             PLAYER_SPEED = PLAYER_SPEED + INCR_SLOW
  887.                         End If
  888.                     End If
  889.                 End If    ;end of the "If we're not in the middle of a hyperjump" IF statement
  890.                 
  891.                 ;this next peice of code updates the player position on the map, relative to it's Speed and Angle and it's last position
  892.                 PLAYER_X = PLAYER_X + (PLAYER_SPEED*(Sin(PLAYER_ANGLE)/2))
  893.                 PLAYER_Y = PLAYER_Y - (PLAYER_SPEED*(Cos(PLAYER_ANGLE)/2))
  894.                 If PLAYER_X < 0 Then                        ;if the PLAYER_X value is less than 0, then wrap your position around the map
  895.                     PLAYER_X = (PLAYER_X + GAME_AREA_X)        ;by adding the GAME_AREA_X value to the negative value, i.e.: -5 becomes 19995 on a 20000 X pixel map.
  896.                 End If
  897.                 If PLAYER_X > GAME_AREA_X Then                ;the same in reverse, i.e. 20004 becomes 4 on the same map.
  898.                     PLAYER_X = (PLAYER_X - GAME_AREA_X)
  899.                 End If
  900.                 If PLAYER_Y < 0 Then                        ;and now the same for the Y direction
  901.                     PLAYER_Y = (PLAYER_Y + GAME_AREA_Y)
  902.                 End If
  903.                 If PLAYER_Y > GAME_AREA_Y Then
  904.                     PLAYER_Y = (PLAYER_Y - GAME_AREA_Y)
  905.                 End If
  906.             End If        ;end of the "If the game is still running ('gameovercounter')" IF Statement
  907.     
  908.             For icon.icons=Each icons                ;the "icons" don't move from their randomly set x,y position, so all we need to do for them is
  909.                 icon\frame = icon\frame+.5            ;update their animation frame number. There are 6 frames, and we're incrementing at 0.5 frames per update.
  910.                 If Int(icon\frame) = 6 Then            ;in real terms, this means we'll be updating the frame number every 2 updates.
  911.                     icon\frame = 0                    ;Because the icon animations are simple 0 to 5 cycling animations, when the frame number reaches 6, we flip it back to 0
  912.                 End If                                ;to start the sequence again.
  913.             Next
  914.             
  915.             ;the following code section is probably the most complex in the game, because it's the Enemy Artificial Intelligence
  916.             ;Reader's of a nervous disposition might want to skip this - I know I did! :)))
  917.             For enemy.enemies=Each enemies        ;for each version of the "enemies" type..
  918.  
  919.                 If enemy\exp_frame > 0 Then                        ;remember before, I said we were going to blow up the player and enemies, just by setting a value?
  920.                     enemy\exp_frame = enemy\exp_frame + .5        ;well, this is it! if this "enemies" exp_frame is greater than 0, then start increasing the Explosion
  921.                 End If                                            ;animation frame number (notice the same "update every two screen refreshes" technique?)
  922.  
  923.                 If cloakon = 0        ;if the player's CLOAKing device is off, then do the following bit. Otherwise, ignore it..
  924.                     ;indeed. This next bit makes the enemies home in on you and shoot you to peices. If your cloak is on, they can't see you, so don't do the intelligence tests
  925.  
  926.                     If enemy\exp_frame = 0 Then            ;as long as this version of "enemies" isn't busy exploding..
  927.  
  928.                         ;this bit checks the distances to the left, right, top and bottom of the enemy, relative to the player, to decide which way to fly would be the best
  929.                         ;intercept route. I tell you, these are vicious dedicated little oiks! :)
  930.                         temp_x1# = PLAYER_X - enemy\x         ;x distance to player on the right
  931.                         temp_y1# = PLAYER_Y - enemy\y        ;y distance to player on the top
  932.                         temp_x2# = enemy\x - PLAYER_X         ;x distance to player on the left
  933.                         temp_y2# = enemy\y - PLAYER_Y        ;y distance to player on the bottom
  934.                         If temp_x1# < 0 Then                    ;if the values are bigger than the game area, or less than 0, then wrap them
  935.                             temp_x1# = temp_x1# + GAME_AREA_X    ;around the game map, like with the player before.
  936.                         End If
  937.                         If temp_x1# > GAME_AREA_X Then
  938.                             temp_x1# = temp_x1# - GAME_AREA_X
  939.                         End If
  940.                         If temp_y1# < 0 Then
  941.                             temp_y1# = temp_y1# + GAME_AREA_Y
  942.                         End If
  943.                         If temp_x1# > GAME_AREA_X Then
  944.                             temp_y1# = temp_y1# - GAME_AREA_Y
  945.                         End If
  946.                         If temp_x2# < 0 Then
  947.                             temp_x2# = temp_x2# + GAME_AREA_X
  948.                         End If
  949.                         If temp_x2# > GAME_AREA_X Then
  950.                             temp_x2# = temp_x2# - GAME_AREA_X
  951.                         End If
  952.                         If temp_y2# < 0 Then
  953.                             temp_y2# = temp_y2# + GAME_AREA_Y
  954.                         End If
  955.                         If temp_x2# > GAME_AREA_X Then
  956.                             temp_y2# = temp_y2# - GAME_AREA_Y
  957.                         End If
  958.  
  959.                         ;this bit compares the two x directions to see which one is smaller            
  960.                         If Abs(temp_x1#) < Abs(temp_x2#) Then    ;the ABS function always gives you the "+VE" version of a number, so -1 comes out as 1 and 2 comes out as 2
  961.                             temp_x# = Abs(temp_x1#)        ;if "Temp_x1" is the smallest, make this the "best" x distance 
  962.                             xdir = -1
  963.                         Else
  964.                             temp_x# = Abs(temp_x2#)        ;otherwise if "Temp_x2" is the smallest, make this the "best" x distance
  965.                             xdir = 1
  966.                         End If
  967.                         If Abs(temp_y1#) < Abs(temp_y2#) Then    ;same with the y directions
  968.                             temp_y# = Abs(temp_y1#)
  969.                             ydir = -1
  970.                         Else
  971.                             temp_y# = Abs(temp_y2#)
  972.                             ydir = 1
  973.                         End If
  974.                         
  975.                         ;because we used the ABS function, we've lost the original direction of the value's units, so using the xdir and ydir
  976.                         ;values we just set over there, we can rebuild that directional picture
  977.                         If xdir = 1 And ydir = 1 Then
  978.                             sector = 4                        ;top left
  979.                         ElseIf xdir = 1 And ydir = -1 Then
  980.                             sector = 3                        ;bottom left
  981.                         ElseIf xdir = -1 And ydir = -1 Then
  982.                             sector = 2                        ;bottom right
  983.                         ElseIf xdir = -1 And ydir = 1 Then
  984.                             sector = 1                        ;top right
  985.                         End If
  986.                         
  987.                         ;finally, we're going to use our knowledge of the shortest distance between this "enemies" and the player
  988.                         ;using PYTHAGORAS theorum to get the angle between them.
  989.  
  990.                         temp_x# = Abs(temp_x# / 200)        ;this bit just makes the number's smaller and more manageable
  991.                         temp_y# = Abs(temp_y# / 200)
  992.                         temp_hyp# = (temp_x#*temp_x#) + (temp_y#*temp_y#)    ;PYTHAGORAS would be proud
  993.                         temp_hyp# = Sqr(temp_hyp#)                            ;.. oh and Mrs Pennington, my Maths teacher! :)
  994.                         enemy\dest_adj = temp_x#        ;these Type properties aren't used anymore, except in the DEBUG version
  995.                         enemy\dest_opp = temp_y#
  996.                         enemy\dest_hyp = temp_hyp#
  997.                         enemy\dest_angle = ASin(temp_y#/temp_hyp#)    ;finally, back to Trigonometry, the angle is revealed.
  998.                         
  999.                         ;now, once again, because we lost the directions of the original value's units, the angle we've just got will only be between 0 and 90 degrees
  1000.                         ;consequently, we've got to decide how to get 91 to 359 degrees back, which we can do with our "sector" values
  1001.                         Select sector
  1002.                             Case 1
  1003.                                 enemy\dest_angle = 90-enemy\dest_angle    ;between 0 and 90
  1004.                             Case 2
  1005.                                 enemy\dest_angle = 90+enemy\dest_angle    ;between 90 and 180
  1006.                             Case 3
  1007.                                 enemy\dest_angle = 270-enemy\dest_angle    ;between 180 and 270
  1008.                             Case 4
  1009.                                 enemy\dest_angle = 270+enemy\dest_angle    ;between 270 and 360
  1010.                         End Select
  1011.                         
  1012.                         ;so, now our enemies know where to point themselves, let's not allow them to just mindlessly run into you!
  1013.                         If temp_hyp# < Rnd(1,1.5) And gameovercounter = 0 Then    ;if the distance between you and them is less than (a small, but random distance)
  1014.                                                                                 ;and the player is alive..
  1015.                             If enemy\bulletlimiter = 0 Then                                ;exactly like the player shooting, the enemie's bullet needs limiting
  1016.                                 enemy\bulletlimiter = 1
  1017.                                 createbullet(enemy\x,enemy\y,enemy\angle,enemy\speed,2)
  1018.                                 sound_enemy_laser_channel = PlaySound(sound_enemy_laser)
  1019.                             End If
  1020.                             whichway = Rand(1,100)                            ;the enemy comes at you, shoots, then flys off in the opposite direction, however,
  1021.                             If whichway > 50 Then                            ;to give it a slightly random element, they can fly off to the left or the right
  1022.                                 enemy\dest_angle = enemy\dest_angle + 180    ;of themselves. This gives them a slightly less "patterny" feel.
  1023.                             Else
  1024.                                 enemy\dest_angle = enemy\dest_angle - 180
  1025.                             End If
  1026.                             enemy\dist_travelled = enemy\dist_to_go            ;cancel their "distance still to travel before changing course" action by
  1027.                                                                             ;prematurely setting the distance travelled to the distance to go value.
  1028.                                                                             
  1029.                             slowdown = 0            ;if the "enemies" is near enough, we don't want him to stop as he turns away from you.
  1030.                         Else
  1031.                             slowdown = 1            ;at greater distances, we do want the "enemies" to stop, turn and then fly at you.. See later..
  1032.                         End If
  1033.     
  1034.                         ;this is the enemy bullet limiter. Essentially, if an enemy fire's a bullet then it can't fire another one until this
  1035.                         ;counter reaches 10. (in another 10 frames, which at 50 fps would be in a fifth of a second.
  1036.                         If enemy\bulletlimiter > 0 Then
  1037.                             enemy\bulletlimiter = enemy\bulletlimiter + 1
  1038.                             If enemy\bulletlimiter = 10 Then ;value essentially sets the enemies fire-rate (the lower the number, the faster the fire rate!)
  1039.                                 enemy\bulletlimiter = 0    ;allows the enemy to fire another bullet.
  1040.                             End If
  1041.                         End If
  1042.                         
  1043.                         ;this bit works out what the destination angle given before looks like in increments of 5 degrees.
  1044.                         ;the angle the enemy *wants* to face is, for example, 212 degrees. The closest angle I drew in Paint Shop Pro is 210 degrees
  1045.                         If enemy\dest_angle >= 360 Then
  1046.                             enemy\dest_angle = enemy\dest_angle - 360
  1047.                         ElseIf enemy\dest_angle < 0 Then
  1048.                             enemy\dest_angle = enemy\dest_angle + 360
  1049.                         End If
  1050.                         ;this next line says does the 212 to 210 conversion, i.e.: 
  1051.                         ;212 / 5 = 42.4
  1052.                         ;42.4 converted to an INTeger is 42
  1053.                         ;5 * 42 = 210
  1054.                         enemy\dest_angle = 5 * Int(enemy\dest_angle / 5)
  1055.             
  1056.                         ;this next section works out the quickest rotation that the "enemies" ship can do to face the direction it wants to be
  1057.                         ;i.e.: if it's currently at 20 degrees, and wants to be facing 45 degrees, then he's got 25 degrees to go to the right, or 335 degrees to the left.
  1058.                         ;guess which one would be more sensible in a life-or-death situation?
  1059.                         If enemy\angle > enemy\dest_angle Then
  1060.                             enemy\rotate_angle = enemy\angle - enemy\dest_angle
  1061.                         ElseIf enemy\angle < enemy\dest_angle
  1062.                             enemy\rotate_angle = 0 - (enemy\dest_angle - enemy\angle)
  1063.                         Else
  1064.                             enemy\rotate_angle = 0
  1065.                         End If
  1066.                         
  1067.                         If enemy\rotate_angle > 180 Then
  1068.                             enemy\rotate_angle = 0-(360-enemy\rotate_angle)
  1069.                         End If
  1070.                         If enemy\rotate_angle < -180 Then
  1071.                             enemy\rotate_angle = (360+enemy\rotate_angle)
  1072.                         End If
  1073.  
  1074.                         ;this bit is working out how far the "enemies" has travelled since the last update and adds it to the "dist_travelled" property
  1075.                         dist_x# = dist_x# + (enemy\speed*(Sin(enemy\angle)/2))
  1076.                         dist_y# = dist_y# - (enemy\speed*(Cos(enemy\angle)/2))
  1077.                         enemy\dist_travelled = enemy\dist_travelled + Sqr((dist_x#*dist_x#) + (dist_y#*dist_y#))
  1078.             
  1079.                         ;Before, we said that the enemy should travel a certain distance before he retargets and homes in on you.
  1080.                         ;this next section deals with the event once the "enemies" has travelled that distance!
  1081.                         If enemy\dist_travelled > enemy\dist_to_go Then
  1082.                             If slowdown = 1 Then                ;depending on the value of "slowdown", the "enemies" will (or will not) slow down as he turns to face you.
  1083.                                 If enemy\speed > 0 Then
  1084.                                     enemy\speed = enemy\speed - (5*INCR_SLOW)
  1085.                                 Else
  1086.                                     enemy\speed = 0
  1087.                                 End If
  1088.                             End If
  1089.                             ;based on the decision made a second ago, about which was the quickest way to rotate to face you fastest..
  1090.                             If enemy\rotate_angle < 0 Then
  1091.                                 If Not enemy\angle = enemy\dest_angle Then
  1092.                                     enemy\angle = enemy\angle + 5                ;rotate the "enemies" right until its angle is correct
  1093.                                     If enemy\angle >=360 Then
  1094.                                         enemy\angle = 360-enemy\angle            ;flip the angle back to 0 when it gets to 360
  1095.                                     End If
  1096.                                 Else
  1097.                                     enemy\dist_to_go = Rnd(ENEMY_MIN_DIST,ENEMY_MAX_DIST)    ;once the angle is correct, randomly create another distance to
  1098.                                     enemy\dist_travelled = 0                                ;travel until the next check, and reset the "travelled" distance to 0
  1099.                                 End If
  1100.                             Else
  1101.                                 If Not enemy\angle = enemy\dest_angle Then
  1102.                                     enemy\angle = enemy\angle - 5                ;exactly the same, but rotating left
  1103.                                     If enemy\angle < 0 Then
  1104.                                         enemy\angle = enemy\angle+360
  1105.                                     End If
  1106.                                 Else
  1107.                                     enemy\dist_to_go = Rnd(ENEMY_MIN_DIST,ENEMY_MAX_DIST)
  1108.                                     enemy\dist_travelled = 0
  1109.                                 End If
  1110.                             End If
  1111.                             
  1112.                         Else    ;if the "enemies" has not reached his destination "distance to go" value then
  1113.                         
  1114.                             If slowdown = 1 Then
  1115.                                 If enemy\speed < enemy\maxspeed Then                ;speed up the enemy until he reaches maximum speed
  1116.                                     enemy\speed = enemy\speed + (5*INCR_SPEED)
  1117.                                 Else
  1118.                                     enemy\speed = enemy\maxspeed
  1119.                                 End If
  1120.                             Else                                                    ;if he's within a certain distance, only allow him to
  1121.                                 If enemy\speed < enemy\maxspeed/2 Then                ;fly at half speed
  1122.                                     enemy\speed = enemy\speed + (5*INCR_SPEED)
  1123.                                 Else
  1124.                                     enemy\speed = enemy\maxspeed / 2
  1125.                                 End If
  1126.                             End If
  1127.                         End If
  1128.                         
  1129.                     End If    ;end of the "is enemy in the middle of exploding" IF statement
  1130.                     
  1131.                 End If    ;end of the "is the Player's CLOAKing device on?" IF statement
  1132.                 
  1133.                 enemy\x = enemy\x + (enemy\speed*(Sin(enemy\angle)/2))        ;update the "enemies" x and y positions, relative to its Speed and Angle
  1134.                 enemy\y = enemy\y - (enemy\speed*(Cos(enemy\angle)/2))        ;exactly the same code as the Player's positions, earlier
  1135.                 If enemy\x < 0 Then
  1136.                     enemy\x = (enemy\x + GAME_AREA_X)
  1137.                 End If
  1138.                 If enemy\x > GAME_AREA_X Then
  1139.                     enemy\x = (enemy\x - GAME_AREA_X)
  1140.                 End If
  1141.                 If enemy\y < 0 Then
  1142.                     enemy\y = (enemy\y + GAME_AREA_X)
  1143.                 End If
  1144.                 If enemy\y > GAME_AREA_Y Then
  1145.                     enemy\y = (enemy\y - GAME_AREA_Y)
  1146.                 End If
  1147.                 
  1148.             Next    ;end of the ENEMIES for loop
  1149.             
  1150.             
  1151.             ;this next bit of code creates the "simple but effective" Hyperjump event, based entirely on the value of "hypercount" being set to 1, earlier in the code.
  1152.             If hypercount > 0 Then
  1153.                 If (hypercount/2 = Int(hypercount/2)) Then    ;this line says "If the value of 'hypercount' is an EVEN number"
  1154.                                                             ;because 5 (an odd number) would be 2.5 when devided by 2, but conversion to an INTeger gives 3.
  1155.                                                             ;2.5 does NOT equal 3!
  1156.                     ;all of this simply rotates the HyperJump ships in different offset directions
  1157.                     ;the only difference is, we're not bothering with degrees here, just animation frame numbers, i.e.: 355 degrees is frame 71 (i.e.: 355/5 degree increment)
  1158.                     frame1 = frame1 + 3
  1159.                     frame2 = frame2 - 3
  1160.                     frame3 = frame1 + 9
  1161.                     frame4 = frame2 - 9
  1162.                     frame5 = frame1 + 36
  1163.                     frame6 = frame2 - 36
  1164.                     frame7 = frame1 + 54
  1165.                     frame8 = frame2 - 54
  1166.                     If frame1 >=72 Then
  1167.                         frame1 = frame1-72
  1168.                     End If
  1169.                     If frame1 < 0 Then
  1170.                         frame1 = frame1+72
  1171.                     End If
  1172.                     If frame2 >=72 Then
  1173.                         frame2 = frame2-72
  1174.                     End If
  1175.                     If frame2 < 0 Then
  1176.                         frame2 = frame2+72
  1177.                     End If
  1178.                     If frame3 >=72 Then
  1179.                         frame3 = frame3-72
  1180.                     End If
  1181.                     If frame3 < 0 Then
  1182.                         frame3 = frame3+72
  1183.                     End If
  1184.                     If frame4 >=72 Then
  1185.                         frame4 = frame4-72
  1186.                     End If
  1187.                     If frame4 < 0 Then
  1188.                         frame4 = frame4+72
  1189.                     End If
  1190.                     If frame5 >=72 Then
  1191.                         frame5 = frame5-72
  1192.                     End If
  1193.                     If frame5 < 0 Then
  1194.                         frame5 = frame5+72
  1195.                     End If
  1196.                     If frame6 >=72 Then
  1197.                         frame6 = frame6-72
  1198.                     End If
  1199.                     If frame6 < 0 Then
  1200.                         frame6 = frame6+72
  1201.                     End If
  1202.                     If frame7 >=72 Then
  1203.                         frame7 = frame7-72
  1204.                     End If
  1205.                     If frame7 < 0 Then
  1206.                         frame7 = frame7+72
  1207.                     End If
  1208.                     If frame8 >=72 Then
  1209.                         frame8 = frame8-72
  1210.                     End If
  1211.                     If frame8 < 0 Then
  1212.                         frame8 = frame8+72
  1213.                     End If
  1214.                 End If    ;end of the "if hypercount is EVEN" IF statement
  1215.                 
  1216.                 ;this bit increases the value of "hypercount" until it reaches 200
  1217.                 hypercount = hypercount + 1
  1218.                 If hypercount > 0 And hypercount <= 102 Then    ;between 0 and 102, the player speed increases
  1219.                     PLAYER_SPEED = PLAYER_SPEED + 2
  1220.                 ElseIf hypercount > 102 And hypercount < 200 Then    ;between 102 and 200, the player speed decreases (but only if FLAG_GAMESTARTER is 0)
  1221.                     If FLAG_GAMESTARTER = 0 Then                    ;this is because when the game starts, the player speed is 0, but we've faked being in
  1222.                         PLAYER_SPEED = PLAYER_SPEED - 2                ;the middle of a hyperjump. Without this FLAG, the player ship would start each game
  1223.                     End If                                            ;travelling at about -90 speed backwards, which would just be weird! :)
  1224.                 End If
  1225.                 If hypercount = 100 Then
  1226.                     game_stars_randomize()    ;half way through the Hyperjump sequence, the "game_starts_randomize()" function is called, which changes all the star positions    
  1227.                                             ;and depths, to give the impression we've moved to a completely different part of space
  1228.                 End If
  1229.                 If hypercount/10 = Int(hypercount/10) Then
  1230.                     game_player_randomize()        ;every 10 updates, the function "game_player_randomize()" is called. This randomly jumps the player around the map
  1231.                                                 ;and confuses the hell out of the bad guys! ;))
  1232.                 End If
  1233.                 If hypercount = 200 Then        ;if the "hypercount" variable reaches 200, then stop the sequence and reset the value back to 0
  1234.                     hypercount = 0
  1235.                     FLAG_GAMESTARTER = 0        ;also, when the game first starts we were in the middle of a hyperjump. Resetting this FLAG back to 0 means that
  1236.                                                 ;the next hyperjump sequence will decrease the speed after "hypercount" gets to 103
  1237.                 End If
  1238.             Else                            ;if we're not in the middle of a hyperjump event, then:
  1239.                 frame1=game_player_frame-1    ;this bit is just for the DEBUG mode. It was designed to check that 360 degrees became 0 degrees and vice versa correctly
  1240.                 frame2=game_player_frame+1
  1241.                 If frame1 < 0 Then
  1242.                     frame1 = frame1 + 72
  1243.                 End If
  1244.                 If frame2 >= 72 Then
  1245.                     frame2 = frame2 - 72
  1246.                 End If
  1247.             End If    ;end of the "Are we in the middle of a Hyperjump" IF statement
  1248.             
  1249.             ;the parralex stars move relative to the player and is just the same "menustars" number of stars
  1250.             ;scrolled at various speeds, wrapping around the screen.
  1251.             ;it's a fairly cheap, but effective way of creating a nice illusion of speed!
  1252.             If starson=1 Then                ;if, at the beginning of the program, you set "starson" to 0, the stars will disappear.
  1253.                                             ;the game would also feel pretty bloody wierd.. hold on.. yep.. Absolutely mad! Try it! :)
  1254.                 For star.stars=Each stars
  1255.                     ;the following two lines move each version of the "stars" Type an x and y distance relative to the player's speed and angle
  1256.                     ;with a devision relative to the depth of the star to make the smallest stars move slower than the biggest
  1257.                     ;thus we have our parallex effect.
  1258.                     
  1259.                     ;it might be of interest to know that these two lines were based on the OLDSKOOL demo which comes with Blitz Basic
  1260.                     ;and was the starting point for the whole CELESTIAL RIFT game concept! Thanks a lot, Mr Mikkel L°kke!! :)
  1261.                     star\y=(star\y+PLAYER_SPEED*(Cos(360-PLAYER_ANGLE)/(6-star\depth+1)))
  1262.                     star\x=(star\x+PLAYER_SPEED*(Sin(360-PLAYER_ANGLE)/(6-star\depth+1)))
  1263.                     ;the maximum pixel width of for the biggest star image is 5 pixels
  1264.                     ;the following IF statements wrap the stars around the screen border when they reach the extremities
  1265.                     If star\x < -5 Then
  1266.                         star\x = star\x + (SCREEN_WIDTH + 5)
  1267.                     End If
  1268.                     If star\x > SCREEN_WIDTH Then
  1269.                         star\x = star\x - (SCREEN_WIDTH + 5)
  1270.                     End If
  1271.                     If star\y <= -5 Then
  1272.                         star\y = star\y + (SCREEN_HEIGHT + 5)
  1273.                     End If
  1274.                     If star\y >= SCREEN_HEIGHT
  1275.                         star\y = star\y - (SCREEN_HEIGHT + 5)
  1276.                     End If
  1277.                 Next
  1278.             End If    ;end of the "are the stars going to be shown" IF statement
  1279.  
  1280.             ;the following lines calculate all the bullet positions, relative to their originally set SPEED and ANGLE from the "createbullet" function.
  1281.             For i = 0 To bulletnum-1
  1282.                 If bullets(i,4) > 0 Then        ;if the bullet isn't 0, i.e.: it's "on"
  1283.                 
  1284.                     bullets(i,0) = bullets(i,0) + (bullets(i,3)*(Sin(bullets(i,2))/2))    ;bullet x position = bullet x position + (bullet speed * (SIN (bullet angle) / 2)
  1285.                     bullets(i,1) = bullets(i,1) - (bullets(i,3)*(Cos(bullets(i,2))/2))    ;bullet y position = bullet y position + (bullet speed * (COS (bullet angle) / 2)
  1286.                                 ;try turning these last two lines off for a crazy pulsing effect of bullets that you can use
  1287.                                 ;to surround the player, creating a kind of enemy-deadly minefield.. Madness! :)
  1288.                     
  1289.                     bullets(i,5) = bullets(i,5) + 1        ;increases the animation frame of the bullet
  1290.                     If bullets(i,5) = 6 Then    ;if the animation frame is 6 then flip it back to 0 (the bullet animation runs frames 0, 1, 2, 3, 4, 5, 0, 1, 2 ... etc)
  1291.                         bullets(i,5) = 0
  1292.                     End If
  1293.                     
  1294.                     ;as with the player and enemies, this next bit wraps the bullets around the map extremities
  1295.                     If bullets(i,0) < 0 Then
  1296.                         bullets(i,0) = (bullets(i,0) + GAME_AREA_X)
  1297.                     End If
  1298.                     If bullets(i,0) > GAME_AREA_X Then
  1299.                         bullets(i,0) = (bullets(i,0) - GAME_AREA_X)
  1300.                     End If
  1301.                     If bullets(i,1) < 0 Then
  1302.                         bullets(i,1) = (bullets(i,1) + GAME_AREA_X)
  1303.                     End If
  1304.                     If bullets(i,1) > GAME_AREA_Y Then
  1305.                         bullets(i,1) = (bullets(i,1) - GAME_AREA_Y)
  1306.                     End If
  1307.                     
  1308.                     ;like the enemies "distance from player", this bit checks if a bullet has gone a certain distance from it's origin
  1309.                     temp_x1# = bullets(i,0) - bullets(i,6) ;origin x on the right
  1310.                     temp_y1# = bullets(i,1) - bullets(i,7) ;origin y on the top
  1311.                     temp_x2# = bullets(i,6) - bullets(i,0) ;origin x on the left
  1312.                     temp_y2# = bullets(i,7) - bullets(i,1) ;origin y on the bottom
  1313.  
  1314.                     ;wraps distances around the map extremities
  1315.                     If temp_x1# < 0 Then
  1316.                         temp_x1# = temp_x1# + GAME_AREA_X
  1317.                     End If
  1318.                     If temp_x1# > GAME_AREA_X Then
  1319.                         temp_x1# = temp_x1# - GAME_AREA_X
  1320.                     End If
  1321.                     If temp_y1# < 0 Then
  1322.                         temp_y1# = temp_y1# + GAME_AREA_Y
  1323.                     End If
  1324.                     If temp_x1# > GAME_AREA_X Then
  1325.                         temp_y1# = temp_y1# - GAME_AREA_Y
  1326.                     End If
  1327.                     If temp_x2# < 0 Then
  1328.                         temp_x2# = temp_x2# + GAME_AREA_X
  1329.                     End If
  1330.                     If temp_x2# > GAME_AREA_X Then
  1331.                         temp_x2# = temp_x2# - GAME_AREA_X
  1332.                     End If
  1333.                     If temp_y2# < 0 Then
  1334.                         temp_y2# = temp_y2# + GAME_AREA_Y
  1335.                     End If
  1336.                     If temp_x2# > GAME_AREA_X Then
  1337.                         temp_y2# = temp_y2# - GAME_AREA_Y
  1338.                     End If
  1339.                     
  1340.                     ;calculates the shortest distance
  1341.                     If Abs(temp_x1#) < Abs(temp_x2#) Then
  1342.                         temp_x# = Abs(temp_x1#)
  1343.                     Else
  1344.                         temp_x# = Abs(temp_x2#)
  1345.                     End If
  1346.                     If Abs(temp_y1#) < Abs(temp_y2#) Then
  1347.                         temp_y# = Abs(temp_y1#)
  1348.                     Else
  1349.                         temp_y# = Abs(temp_y2#)
  1350.                     End If
  1351.                     
  1352.                     ;back to PYTHAGORAS to work out the "As the crow flies" distance from the bullet's original starting point
  1353.                     temp_x# = Abs(temp_x# / 200)
  1354.                     temp_y# = Abs(temp_y# / 200)
  1355.                     temp_hyp# = (temp_x#*temp_x#) + (temp_y#*temp_y#)
  1356.                     temp_hyp# = Sqr(temp_hyp#)
  1357.  
  1358.                     ;if the bullet has travelled "5" units from it's starting point, then..
  1359.                     If temp_hyp# > 5 Then
  1360.                         bullets(i,4) = 0    ;turn the bullet off
  1361.                     End If
  1362.                 End If
  1363.             Next    ;end of bullet coordinate repositioning loop
  1364.             
  1365.             ;this is the player's bullet limiting code, which follows exactly the same logic as the "enemies" code, earlier
  1366.             If bulletlimiter > 0 Then
  1367.                 bulletlimiter = bulletlimiter + 1
  1368.                 If bulletlimiter = 10 Then ;value essentially sets the fire-rate (the lower the number, the faster the fire rate!)
  1369.                     bulletlimiter = 0
  1370.                 End If
  1371.             End If
  1372.             
  1373.             ;calculate player explosions, using the "one frame advance every two screen updates" idea from before
  1374.             If player_explosion_frame > 0 Then
  1375.                 player_explosion_frame = player_explosion_frame + .5
  1376.                 If player_explosion_frame > 26 Then
  1377.                     player_explosion_frame = 26
  1378.                 End If
  1379.             End If
  1380.             
  1381.             ;this bit of code is fired when the player dies (gameovercounter is set to 1)
  1382.             ;and acts exactly the same as "menu_frame", in that it allows us to flash the words "GAME OVER" on and off!
  1383.             If gameovercounter > 0 Then
  1384.                 PLAYER_SPEED = PLAYER_SPEED - INCR_SLOW        ;slow the player speed gradually to 0 when the game ends
  1385.                 If PLAYER_SPEED <= 0 Then                    ;a nice "That's the end for you" statement if you die in mid-battle!
  1386.                     PLAYER_SPEED = 0
  1387.                 End If
  1388.                 gameovercounter = gameovercounter + 1
  1389.                 If gameovercounter = 25 Then
  1390.                     gameovercounter = 1
  1391.                     If gameoverstat = 1 Then
  1392.                         gameoverstat = 0
  1393.                     Else
  1394.                         gameoverstat = 1
  1395.                     End If
  1396.                 End If
  1397.             Else
  1398.                 PLAYER_SCORE = PLAYER_SCORE + 1        ;if the game is in progress still, then increase the PLAYER_SCORE by 1 every screen update
  1399.                                                     ;this acts as a kind of survival bonus for the more defensive player
  1400.             End If
  1401.             
  1402.             ;here's that copied code again, which turns 231 into "0000231", this time
  1403.             ;using PLAYER_SCORE and HI_SCORE as opposed to LAST_SCORE
  1404.             If PLAYER_SCORE < 10 Then
  1405.                 PLAYER_SCORE_STR = "000000"+Str(PLAYER_SCORE)
  1406.             ElseIf PLAYER_SCORE >=10 And PLAYER_SCORE < 100 Then
  1407.                 PLAYER_SCORE_STR = "00000"+Str(PLAYER_SCORE)
  1408.             ElseIf PLAYER_SCORE >=100 And PLAYER_SCORE < 1000 Then
  1409.                 PLAYER_SCORE_STR = "0000"+Str(PLAYER_SCORE)
  1410.             ElseIf PLAYER_SCORE >=1000 And PLAYER_SCORE < 10000 Then
  1411.                 PLAYER_SCORE_STR = "000"+Str(PLAYER_SCORE)
  1412.             ElseIf PLAYER_SCORE >=10000 And PLAYER_SCORE < 100000 Then
  1413.                 PLAYER_SCORE_STR = "00"+Str(PLAYER_SCORE)
  1414.             ElseIf PLAYER_SCORE >=100000 And PLAYER_SCORE < 1000000 Then
  1415.                 PLAYER_SCORE_STR = "0"+Str(PLAYER_SCORE)
  1416.             ElseIf PLAYER_SCORE >=100000 And PLAYER_SCORE < 10000000 Then
  1417.                 PLAYER_SCORE_STR = Str(PLAYER_SCORE)
  1418.             Else
  1419.                 PLAYER_SCORE_STR = "9999999"
  1420.             End If
  1421.             If PLAYER_SCORE >= HI_SCORE Then
  1422.                 HI_SCORE = PLAYER_SCORE
  1423.                 If HI_SCORE < 10 Then
  1424.                     HI_SCORE_STR = "000000"+Str(HI_SCORE)
  1425.                 ElseIf HI_SCORE >=10 And HI_SCORE < 100 Then
  1426.                     HI_SCORE_STR = "00000"+Str(HI_SCORE)
  1427.                 ElseIf HI_SCORE >=100 And HI_SCORE < 1000 Then
  1428.                     HI_SCORE_STR = "0000"+Str(HI_SCORE)
  1429.                 ElseIf HI_SCORE >=1000 And HI_SCORE < 10000 Then
  1430.                     HI_SCORE_STR = "000"+Str(HI_SCORE)
  1431.                 ElseIf HI_SCORE >=10000 And HI_SCORE < 100000 Then
  1432.                     HI_SCORE_STR = "00"+Str(HI_SCORE)
  1433.                 ElseIf HI_SCORE >=100000 And HI_SCORE < 1000000 Then
  1434.                     HI_SCORE_STR = "0"+Str(HI_SCORE)
  1435.                 ElseIf HI_SCORE >=100000 And HI_SCORE < 10000000 Then
  1436.                     HI_SCORE_STR = Str(HI_SCORE)
  1437.                 Else
  1438.                     HI_SCORE_STR = "9999999"
  1439.                 End If
  1440.             End If
  1441.         End If ;end of "IF FLAG_PAUSE = 0" IF Statement
  1442.         
  1443.         ;this flashes the "PAUSED" caption on and off when needs be!
  1444.         game_pause_frame = game_pause_frame + 1
  1445.         If game_pause_frame = 25 Then
  1446.             game_pause_frame = 1
  1447.             game_accept_pause = 1
  1448.             If game_pause_stat = 1 Then
  1449.                 game_pause_stat = 0
  1450.             Else
  1451.                 game_pause_stat = 1
  1452.             End If
  1453.         End If
  1454.  
  1455.     Next    ;end of the "for i = 1 to frames" FOR loop
  1456.     
  1457.     game_draw_update()    ;finally, draw all the pictures on the screen, based on their (possibly) new positions.
  1458. End Function
  1459.  
  1460. ;this function draws the game graphics in their freshly calculated positions
  1461. Function game_draw_update()
  1462.     SetBuffer BackBuffer()    ;draw all of the following to the backbuffer
  1463.     ClsColor 0,0,0            ;changes the CLearScreen colour to black (0,0,0)
  1464.     Cls
  1465.     TileBlock game_background,0,0    ;This acts as a CLear Screen, even if the Resolution is set bigger than "game_background"'s image size
  1466.     If starson=1 Then        ;draw all of the stars using their correct pictures, at the correct x and y positions
  1467.         For star.stars=Each stars ;(for each star in type 'stars' do the following..)
  1468.             DrawImage game_stars(star\depth),star\x,star\y    ;using the depth property of "stars" as the Array position
  1469.         Next
  1470.     End If
  1471.     
  1472.         ;this FOR Type loop draws all the versions of "icons" at their screen-position - relative to the PLAYER coordinates
  1473.         ;in the current animation frame. It also checks for the non-transparent areas of the ICON image touching the non-
  1474.         ;transparent areas of the PLAYER image and updates the PLAYER's relavent energy-level values.
  1475.         For icon.icons=Each icons
  1476.         
  1477.             ;this line draws the relavant icon image at coordinates "x" and "y" on (or off) the screen
  1478.             ;the correct icon image is chosen using the "icons"'s style as it's array position
  1479.             ;the x and y coordinates are worked out by subtracting the PLAYER's current position from the "icons"'s current position
  1480.             ;notice that we're using the same style of "SCREEN_WIDTH\2 - Half the ImageWidth of the Image" idea from the
  1481.             ;"menu_draw_update()" code?
  1482.             DrawImage game_icons(icon\style), (((SCREEN_WIDTH/2)-ImageWidth(game_icons(icon\style))/2) - (PLAYER_X - icon\x)), (((SCREEN_HEIGHT/2)-ImageWidth(game_icons(icon\style))/2) - (PLAYER_Y - icon\y)),Int(icon\frame)
  1483.  
  1484.             ;this line uses the command "ImagesCollide" to place a value in the variable "checkcol" which we didn't declare as a Global
  1485.             ;variable earlier. This is because it is only used once and then discarded.
  1486.             ;Images collide requires the following parameters (information):
  1487.             ;1. image1 name
  1488.             ;2. image1 x position
  1489.             ;3. image1 y position
  1490.             ;4. image1 animation frame number
  1491.             ;5. image2 name
  1492.             ;6. image2 x position
  1493.             ;7. image2 y position
  1494.             ;8. image2 animation frame number
  1495.             ;if the two images collide (at least one non-transparent pixel from each image is touching eachother) then
  1496.             ;"checkcol" will equal 1, otherwise it will equal 0 (no non-transparent pixels were touching)
  1497.             checkcol = ImagesCollide(game_icons(icon\style), (((SCREEN_WIDTH/2)-ImageWidth(game_icons(icon\style))/2) - (PLAYER_X - icon\x)), (((SCREEN_HEIGHT/2)-ImageWidth(game_icons(icon\style))/2) - (PLAYER_Y - icon\y)),Int(icon\frame),game_player,(SCREEN_WIDTH/2)-ImageWidth(game_player)/2,(SCREEN_HEIGHT/2)-ImageHeight(game_player)/2,game_player_frame)
  1498.             
  1499.             ;this IF statement says what to do when the two images *have* collided (and the game is still in progress, i.e.: gameovercounter isn't 1)
  1500.             If checkcol=1 And gameovercounter = 0 Then
  1501.             
  1502.                 sound_icon_channel = PlaySound(sound_icon)    ;plays the "icon" sound on it's appropriate channel
  1503.  
  1504.                 Select icon\style    ;back to SELECT..CASE statements, "Which type of icon has the player just collected?"
  1505.                     Case 1
  1506.                         
  1507.                         PLAYER_BOOSTERS = PLAYER_BOOSTERS + BONUS_BOOSTERS    ;add some extra points to the PLAYER_BOOSTERS value..
  1508.                         If PLAYER_BOOSTERS > 192 Then                        ;and check that it isn't full
  1509.                             PLAYER_BOOSTERS = 192
  1510.                         End If
  1511.                     Case 2
  1512.                         PLAYER_SHIELD = PLAYER_SHIELD + BONUS_SHIELD        ;add some points to the PLAYER_SHIELD
  1513.                         If PLAYER_SHIELD > 192 Then    
  1514.                             PLAYER_SHIELD = 192
  1515.                         End If
  1516.                     Case 3
  1517.                         PLAYER_CLOAK = PLAYER_CLOAK + BONUS_CLOAK            ;add some points to the PLAYER_CLOAK
  1518.                         If PLAYER_CLOAK > 192 Then    
  1519.                             PLAYER_CLOAK = 192
  1520.                         End If
  1521.                     Case 4
  1522.                         PLAYER_JUMPS = PLAYER_JUMPS + 1            ;this gives the PLAYER and extra Hyperjump icon
  1523.                         If PLAYER_JUMPS > 5 Then                ;the maximum of which is 5, so cap the PLAYER_JUMPS value at 5
  1524.                             PLAYER_JUMPS = 5
  1525.                         End If
  1526.                 End Select
  1527.                 icon\x = Rnd(0,GAME_AREA_X)                            ;once collected, an icon just reappears at a random point on the map
  1528.                 icon\y = Rnd(0,GAME_AREA_Y)
  1529.                 PLAYER_SCORE = PLAYER_SCORE + SCORE_ICONCOLLECT        ;additionally, a player scores some points for collecting an icon
  1530.             End If
  1531.         Next    ;end of the "icons" FOR loop
  1532.     
  1533.         ;similarly, this Type FOR loop goes through each enemy, drawing it at it's new position (relative to the player)
  1534.         ;and checks for collisions with the player.
  1535.         For enemy.enemies=Each enemies
  1536.         
  1537.             ;this bit confirms what angle to draw each "enemies" at (which animation frame)
  1538.             temp_enemy1_frame = enemy\angle/5
  1539.             If temp_enemy1_frame >= 72 Then
  1540.                 temp_enemy1_frame = temp_enemy1_frame - 72
  1541.             End If
  1542.             If temp_enemy1_frame < 0 Then
  1543.                 temp_enemy1_frame = temp_enemy1_frame + 72
  1544.             End If
  1545.             
  1546.             ;as long as the enemy isn't dead (busy exploding), then draw the enemy at it's x,y position and
  1547.             ;check for collisions with the player.
  1548.             If enemy\exp_frame = 0 Then
  1549.             
  1550.                 ;exactly the same as the icons, relative to the player position. The fact that an enemy moves it's x and y position is irrelevant, because
  1551.                 ;it's new position was already worked out in the last function ("game_loop_update()")
  1552.                 DrawImage game_enemy1, (((SCREEN_WIDTH/2)-ImageWidth(game_enemy1)/2) - (PLAYER_X - enemy\x)), (((SCREEN_HEIGHT/2)-ImageWidth(game_enemy1)/2) - (PLAYER_Y - enemy\y)),temp_enemy1_frame
  1553.  
  1554.                 ;the same collision detection as an "icons" occurs for each enemy colliding with the player
  1555.                 checkcol = ImagesCollide(game_enemy1, (((SCREEN_WIDTH/2)-ImageWidth(game_enemy1)/2) - (PLAYER_X - enemy\x)), (((SCREEN_HEIGHT/2)-ImageWidth(game_enemy1)/2) - (PLAYER_Y - enemy\y)),temp_enemy1_frame,game_player,(SCREEN_WIDTH/2)-ImageWidth(game_player)/2,(SCREEN_HEIGHT/2)-ImageHeight(game_player)/2,game_player_frame)
  1556.  
  1557.                 If checkcol=1 And gameovercounter = 0 Then        ;if the two images have collided (this version of "enemies" and the PLAYER)
  1558.  
  1559.                     PLAYER_SHIELD = PLAYER_SHIELD - DAMAGE_ENEMY_BASH        ;subtract some points off the player's SHIELD
  1560.  
  1561.                     If PLAYER_SHIELD < 0 Then            ;if the player's shield is less than 0, then
  1562.  
  1563.                         PLAYER_SHIELD = 0                ;set the player's shield back to it's minimum value
  1564.                         gameovercounter = 1                ;set the "game is still in progress" variable to 1 (i.e.: the game isn't running anymore)
  1565.                                                         ;in a second, this will start a chain of reaction in "game_loop_update" which make's the player
  1566.                                                         ;image be replaced by the explosion, followed shortly by the "GAME OVER" caption
  1567.  
  1568.                         explosion1or2 = Rnd(0,100)                                    ;there are 2 explosion sound effects (for variation)
  1569.                                                                                     ;this line creates a random number between 0 and 100
  1570.                                                                                     ;(I could just have well have used 0 and 1 and got near
  1571.                                                                                     ;enought the same probability of explosion 1 or 2 variation)
  1572.                                                                                     
  1573.                         If explosion1or2 > 49 Then                                    ;if the random number was greater than 49, then..
  1574.                         
  1575.                             sound_explosion_channel = PlaySound(sound_explosion1)        ;play Explosion sound number 1 on the explosion channel
  1576.  
  1577.                         Else                                                        ;if the number was 49 or less, then..
  1578.  
  1579.                             sound_explosion_channel = PlaySound(sound_explosion2)        ;play Explosion sound number 1 on the explosion channel
  1580.                         End If
  1581.  
  1582.                         player_explosion_frame = 1        ;set the player_explosion_frame to 1 (which in game_loop_update() will start the explosion image sequence)
  1583.                     End If
  1584.                     
  1585.                     If ChannelPlaying(sound_collision_channel) = False Then        ;once again, because this sample will be triggered multiple times as an enemy image
  1586.                                                                                 ;passes through the player image (i.e.: the enemy really rammed you, as opposed to
  1587.                                                                                 ;just catching you), we must allow for the echoing sample overlap (that we last saw
  1588.                                                                                 ;when the player pressed the BOOST or CLOAK key in game_loop_update() )
  1589.                                                                                 
  1590.                                                                                 ;so, "As long as the sample isn't already playing.."
  1591.                         sound_collision_channel = PlaySound(sound_collision)    ;play the "Collision" sound on it's appropriate channel reference
  1592.                     End If
  1593.                     
  1594.                     enemy\energy = enemy\energy - DAMAGE_PLAYER_BASH    ;the enemy also suffers damage for this collision
  1595.                     PLAYER_SCORE = PLAYER_SCORE + SCORE_ENEMYCOLLIDE    ;and the player scores some points
  1596.  
  1597.                     If enemy\energy <= 0 Then                    ;check to see if the "enemies"'s energy is 0 or less and
  1598.                         enemy\energy = 0                        ;cap it at it's minimum value (0)
  1599.  
  1600.                         explosion1or2 = Rnd(0,100)                        ;work out which of the two explosion sounds we'll use..
  1601.                         If explosion1or2 > 49 Then
  1602.                             sound_explosion_channel = PlaySound(sound_explosion1)
  1603.                         Else
  1604.                             sound_explosion_channel = PlaySound(sound_explosion2)
  1605.                         End If
  1606.                         enemy\exp_frame = 1            ;set the "enemies" exp_frame to 1 (which in game_loop_update() will start the explosion image sequence for this
  1607.                                                     ;version of "enemies")
  1608.                     End If
  1609.                 End If
  1610.  
  1611.             Else    ;if this "enemies" *was* in the middle of exploding, then
  1612.             
  1613.                 ;there are 25 frames in the Explosion animation, so when the explosion frame reaches 26, we don't want to draw *anything* any more!
  1614.                 If enemy\exp_frame <= 25 Then
  1615.                 
  1616.                     ;draw frames 1 to 25 at the "enemies" (still moving) postion, but instead of altering the
  1617.                     ;draw position for the Enemy image width/height, we alter it for the Explosion image width/height)
  1618.                     DrawImage game_explosion,(((SCREEN_WIDTH/2)-ImageWidth(game_explosion)/2) - (PLAYER_X - enemy\x)),(((SCREEN_HEIGHT/2)-ImageHeight(game_explosion)/2) - (PLAYER_Y - enemy\y)),Int(enemy\exp_frame-1)
  1619.  
  1620.                 Else                            ;once the explosion has run to it's last frame (it will now be at enemy\frame = 26)..
  1621.  
  1622.                     enemy\x=Rnd(0,GAME_AREA_X)            ;randomize this "enemies"'s position on the map
  1623.                     enemy\y=Rnd(0,GAME_AREA_Y)
  1624.                     enemy\energy = 100                    ;give it it's energy back..
  1625.                     enemy\angle = Int(Rnd(0,72)) * 5
  1626.                     enemy\maxspeed = Rnd(20,40)            ;reset it's speed abilities
  1627.                     enemy\speed = 0                        ;start the new generation of this "enemies" in a static position (as if it's just hyperjumped in!)
  1628.                     enemy\style = 1
  1629.                     enemy\exp_frame = 0                    ;stop it exploding!
  1630.                     
  1631.                     enemy\dist_to_go = Rnd(ENEMY_MIN_DIST,ENEMY_MAX_DIST)
  1632.                     enemy\dist_travelled = 0
  1633.                     enemy\gen=enemy\gen +1        ;remember before, I said that the enemy would be worth more points as it regenerated?
  1634.                                                 ;here it is! If this was the first time it had been killed, next time will be worth *TWICE* the points
  1635.                                                 ;if it was the 5th time it had been killed, next time it will be worth *SIX* times the points etc..
  1636.                                                 
  1637.                 End If
  1638.             End If        ;end of the "is this enemies exploding" IF statement
  1639.         Next    ;end of the "enemies" FOR loop
  1640.  
  1641.         ;now we'll do the same for all the bullets on (or off) the screen    
  1642.         For i = 0 To bulletnum-1    ;this cycles though the array from position 1 to the final bullet number in the array..
  1643.                                     ;we use "bulletnum - 1" because there are (for example) 600 possible bullets that are stored
  1644.                                     ;in an array as 0, 1, 2, 3 ... 596, 597, 598 and 599
  1645.         
  1646.             Select bullets(i,4)        ;whose bullet is it? remember when we originally DIMmed this Array, I said that 0 was off, 1 was a PLAYER bullet and 2 was an enemy bullet?
  1647.                 Case 1
  1648.                 
  1649.                     ;if it's a player bullet then..
  1650.                     ;draw this bullet at it's position, relative to the player, in it's current animation frame
  1651.                     DrawImage game_bullet_player,(((SCREEN_WIDTH/2)-ImageWidth(game_bullet_player)/2) - (PLAYER_X - bullets(i,0))), (((SCREEN_HEIGHT/2)-ImageWidth(game_bullet_player)/2) - (PLAYER_Y - bullets(i,1))),bullets(i,5)
  1652.  
  1653.                     ;this checks for collisions with this bullet and all the enemies..
  1654.                     For enemy.enemies = Each enemies
  1655.                         If enemy\exp_frame = 0 Then        ;.. as long as an enemy isn't already exploding..
  1656.  
  1657.                             ;to get the x and y positions for each image, I have just copied and pasted their original DRAWIMAGE parameters into this statement
  1658.                             ;watch out more missing off brackets and values..                        
  1659.                             checkcol = ImagesCollide(game_enemy1, (((SCREEN_WIDTH/2)-ImageWidth(game_enemy1)/2) - (PLAYER_X - enemy\x)), (((SCREEN_HEIGHT/2)-ImageWidth(game_enemy1)/2) - (PLAYER_Y - enemy\y)),temp_enemy1_frame,game_bullet_player,(((SCREEN_WIDTH/2)-ImageWidth(game_bullet_player)/2) - (PLAYER_X - bullets(i,0))), (((SCREEN_HEIGHT/2)-ImageWidth(game_bullet_player)/2) - (PLAYER_Y - bullets(i,1))),bullets(i,5))
  1660.  
  1661.                             If checkcol = 1 And gameovercounter = 0 Then     ;if the bullet hit the enemy (and the game isn't over) then
  1662.                                 bullets(i,4) = 0                                            ;turn off the bullet (effectively makes it disappear!)
  1663.                                 enemy\energy = enemy\energy - DAMAGE_ENEMY_IS_SHOT                ;take off some points from the "enemies"'s shield
  1664.                                 PLAYER_SCORE = PLAYER_SCORE + enemy\gen*SCORE_ENEMY_IS_SHOT        ;give the player points for the shot, with the 
  1665.                                                                                                 ;"enemies"'s GENeration value as a multiplier!
  1666.  
  1667.                                 ricochet1or2 = Rnd(0,100)                                    ;similarly to explosions, there are two ricochet sounds
  1668.                                 If ricochet1or2 > 49 Then
  1669.                                     sound_bullethit_channel = PlaySound(sound_bullethit1)
  1670.                                 Else
  1671.                                     sound_bullethit_channel = PlaySound(sound_bullethit2)
  1672.                                 End If
  1673.                             End If
  1674.                             If enemy\energy <= 0 Then                    ;checks to see if we've just killed the enemy!
  1675.                                 enemy\energy = 0
  1676.                                 explosion1or2 = Rnd(0,100)                            ;if we have, then play 1 of the two explosion sound effects..
  1677.                                 If explosion1or2 > 49 Then
  1678.                                     sound_explosion_channel = PlaySound(sound_explosion1)
  1679.                                 Else
  1680.                                     sound_explosion_channel = PlaySound(sound_explosion2)
  1681.                                 End If
  1682.                                 enemy\exp_frame = 1                        ;starts off the enemy explosion chain reaction in "game_loop_update()"
  1683.                             End If
  1684.                         End If        ;end of the "is enemy already dead" IF statement
  1685.                     Next    ;end of checking through each "enemies" FOR loop
  1686.                         
  1687.                 Case 2
  1688.                 
  1689.                     ;if it's an enemy bullet then..
  1690.                     ;draw this bullet at it's position, relative to the player, in it's current animation frame
  1691.                     DrawImage game_bullet_enemy1,(((SCREEN_WIDTH/2)-ImageWidth(game_bullet_enemy1)/2) - (PLAYER_X - bullets(i,0))), (((SCREEN_HEIGHT/2)-ImageWidth(game_bullet_enemy1)/2) - (PLAYER_Y - bullets(i,1))),bullets(i,5)
  1692.  
  1693.                     checkcol = ImagesCollide(game_bullet_enemy1,(((SCREEN_WIDTH/2)-ImageWidth(game_bullet_enemy1)/2) - (PLAYER_X - bullets(i,0))), (((SCREEN_HEIGHT/2)-ImageWidth(game_bullet_enemy1)/2) - (PLAYER_Y - bullets(i,1))),bullets(i,5),game_player,(SCREEN_WIDTH/2)-ImageWidth(game_player)/2,(SCREEN_HEIGHT/2)-ImageHeight(game_player)/2,game_player_frame)
  1694.  
  1695.                     If checkcol = 1 And gameovercounter = 0 Then                    ;if the bullet hit the player, and the game isn't already over..
  1696.  
  1697.                         PLAYER_SHIELD = PLAYER_SHIELD - DAMAGE_PLAYER_IS_SHOT        ;subtract some points from the PLAYER's SHIELD
  1698.  
  1699.                         ricochet1or2 = Rnd(0,100)                                    ;play one of the two ricochet sound effects..
  1700.                         If ricochet1or2 > 49 Then
  1701.                             sound_bullethit_channel = PlaySound(sound_bullethit1)
  1702.                         Else
  1703.                             sound_bullethit_channel = PlaySound(sound_bullethit2)
  1704.                         End If
  1705.                         bullets(i,4) = 0                    ;turn the bullet off..
  1706.                     End If
  1707.  
  1708.                     If PLAYER_SHIELD < 0 Then        ;checks to see if the player's SHIELD is less than 0
  1709.                         PLAYER_SHIELD = 0                ;caps the shield at it's minimum (0)
  1710.  
  1711.                         gameovercounter = 1            ;sets the "the game is over" variable to 1
  1712.  
  1713.                         explosion1or2 = Rnd(0,100)                                    ;chooses and plays the sound effect for one of our two explosion noises
  1714.                         If explosion1or2 > 49 Then
  1715.                             sound_explosion_channel = PlaySound(sound_explosion1)
  1716.                         Else
  1717.                             sound_explosion_channel = PlaySound(sound_explosion2)
  1718.                         End If
  1719.                         player_explosion_frame = 1    ;starts the player explosion chain reaction back in "game_loop_update"
  1720.                     End If
  1721.             End Select
  1722.         Next    ;end of the "bullet drawing/collision detecting" FOR loop
  1723.  
  1724.     ;this section draws the frames of "animation" for the hyperjump, or - if we're not mid hyperjump - draws the regular player frames
  1725.     ;the hyperjump bits look quite complecated, but it's just x and y positions that are changing in relation to the value of "hypercount"
  1726.     If hypercount > 0 And hypercount < 100 Then
  1727.         If hypercount/2 = Int(hypercount/2) Then        ;if the value of "hypercount" is EVEN then..
  1728.                                                         ;draw these four pictures
  1729.             DrawImage game_player,(SCREEN_WIDTH/2)-ImageWidth(game_player)/2+hypercount,(SCREEN_HEIGHT/2)-ImageHeight(game_player)/2-hypercount,frame2
  1730.             DrawImage game_player,(SCREEN_WIDTH/2)-ImageWidth(game_player)/2+hypercount,(SCREEN_HEIGHT/2)-ImageHeight(game_player)/2+hypercount,frame4
  1731.             DrawImage game_player,(SCREEN_WIDTH/2)-ImageWidth(game_player)/2-hypercount,(SCREEN_HEIGHT/2)-ImageHeight(game_player)/2+hypercount,frame6
  1732.             DrawImage game_player,(SCREEN_WIDTH/2)-ImageWidth(game_player)/2-hypercount,(SCREEN_HEIGHT/2)-ImageHeight(game_player)/2-hypercount,frame8
  1733.  
  1734.         Else                                            ;otherwise, if the value of "hypercount" is ODD, then..
  1735.                                                         ;draw these four pictures..
  1736.                                                         ;this ODD/EVEN swapping results in our "flickery" effect, but you
  1737.                                                         ;can see the distinct 4 pictures if you PAUSE the game in the middle of a jump!
  1738.             DrawImage game_player,(SCREEN_WIDTH/2)-ImageWidth(game_player)/2-(1.4*hypercount),(SCREEN_HEIGHT/2)-ImageHeight(game_player)/2,frame7
  1739.             DrawImage game_player,(SCREEN_WIDTH/2)-ImageWidth(game_player)/2,(SCREEN_HEIGHT/2)-ImageHeight(game_player)/2+(1.4*hypercount),frame5
  1740.             DrawImage game_player,(SCREEN_WIDTH/2)-ImageWidth(game_player)/2+(1.4*hypercount),(SCREEN_HEIGHT/2)-ImageHeight(game_player)/2,frame3
  1741.             DrawImage game_player,(SCREEN_WIDTH/2)-ImageWidth(game_player)/2,(SCREEN_HEIGHT/2)-ImageHeight(game_player)/2-(1.4*hypercount),frame1
  1742.         End If
  1743.     ElseIf hypercount >= 100 And hypercount < 200 Then    ;between 0 and 100, the 8 "ships" move outwards from the middle..
  1744.                                                         ;after that, they converge back to the centre, using exactly the same code, but "200 - hypercount"
  1745.                                                         ;instead of "hypercount". It's a cheap effect that didn't cost me any more Paint Shop Pro time
  1746.                                                         ;and it looks quite cool! :)
  1747.         If hypercount/2 = Int(hypercount/2) Then
  1748.             DrawImage game_player,(SCREEN_WIDTH/2)-ImageWidth(game_player)/2+(200-hypercount),(SCREEN_HEIGHT/2)-ImageHeight(game_player)/2-(200-hypercount),frame2
  1749.             DrawImage game_player,(SCREEN_WIDTH/2)-ImageWidth(game_player)/2+(200-hypercount),(SCREEN_HEIGHT/2)-ImageHeight(game_player)/2+(200-hypercount),frame4
  1750.             DrawImage game_player,(SCREEN_WIDTH/2)-ImageWidth(game_player)/2-(200-hypercount),(SCREEN_HEIGHT/2)-ImageHeight(game_player)/2+(200-hypercount),frame6
  1751.             DrawImage game_player,(SCREEN_WIDTH/2)-ImageWidth(game_player)/2-(200-hypercount),(SCREEN_HEIGHT/2)-ImageHeight(game_player)/2-(200-hypercount),frame8
  1752.         Else
  1753.             DrawImage game_player,(SCREEN_WIDTH/2)-ImageWidth(game_player)/2-(1.4*(200-hypercount)),(SCREEN_HEIGHT/2)-ImageHeight(game_player)/2,frame7
  1754.             DrawImage game_player,(SCREEN_WIDTH/2)-ImageWidth(game_player)/2,(SCREEN_HEIGHT/2)-ImageHeight(game_player)/2+(1.4*(200-hypercount)),frame5
  1755.             DrawImage game_player,(SCREEN_WIDTH/2)-ImageWidth(game_player)/2+(1.4*(200-hypercount)),(SCREEN_HEIGHT/2)-ImageHeight(game_player)/2,frame3
  1756.             DrawImage game_player,(SCREEN_WIDTH/2)-ImageWidth(game_player)/2,(SCREEN_HEIGHT/2)-ImageHeight(game_player)/2-(1.4*(200-hypercount)),frame1
  1757.         End If
  1758.  
  1759.     Else            ;if, on the other hand, we're not mid-hyperjump, then we'll just be drawing the normal player frames..
  1760.     
  1761.         ;checks to see that the angle we want to draw the frame for is 0 to 71 (as 360 degrees is the same as 0 degrees!)
  1762.         game_player_frame = PLAYER_ANGLE/5
  1763.         If game_player_frame = 72 Then
  1764.             game_player_frame = 0
  1765.         End If
  1766.         
  1767.         ;as long as the player isn't busy exploding..
  1768.         If player_explosion_frame = 0 Then
  1769.  
  1770.             If cloakon = 0 Then        ;if the "cloaking device" is off, then draw the player every screen update..
  1771.                 DrawImage game_player,(SCREEN_WIDTH/2)-ImageWidth(game_player)/2,(SCREEN_HEIGHT/2)-ImageHeight(game_player)/2,game_player_frame
  1772.  
  1773.             Else                    ;if the "cloaking device" is on, only draw the player when the "cloakon" number is EVEN..
  1774.                                     ;this is our flickering effect used again..
  1775.                 If cloakon/2 = Int(cloakon/2) Then
  1776.                     DrawImage game_player,(SCREEN_WIDTH/2)-ImageWidth(game_player)/2,(SCREEN_HEIGHT/2)-ImageHeight(game_player)/2,game_player_frame
  1777.                 End If
  1778.             End If
  1779.         Else
  1780.                     ;if, on the other hand, the player *is* busy exploding, then..
  1781.                     
  1782.             If player_explosion_frame <= 25 Then        ;draw frames 1 to 25 of the explosion animation (in the player's position), taking into account
  1783.                                                         ;the Explosion image size, rather than the player image size..
  1784.                 DrawImage game_explosion,(SCREEN_WIDTH/2)-ImageWidth(game_explosion)/2,(SCREEN_HEIGHT/2)-ImageHeight(game_explosion)/2,Int(player_explosion_frame-1)
  1785.             End If
  1786.         End If
  1787.     End If
  1788.     
  1789.     ;As we said before, the foremost pictures are drawn last in our Video collage.
  1790.     ;the following lines draw the "HUD" display stuff like the radar and power bars.
  1791.     ;All of the images are drawn in Paint Shop and then a Magenta pixel is drawn every-other pixel on the image,
  1792.     ;so that when drawn on-screen in the program, some of the pixels beneath the image can be seen, wherever
  1793.     ;there is one of these Magenta (which we made transparent earilier) pixels.
  1794.     ;this gives a cheap and fast version of Cemi-transparency that you'd probably get in a C++ version of the game.
  1795.     DrawImage game_radar,SCREEN_WIDTH-210,3
  1796.     DrawImage game_shields,SCREEN_WIDTH-210,223
  1797.  
  1798.     ;after drawing the "SHIELDS" box, we want to draw "how much" SHIELD the player has left.
  1799.     ;the "game_levels" image is 192 pixels by 20 pixels in size. Because the PLAYER_SHIELD value
  1800.     ;runs from 0 to 192 pixels, we can simply draw the first PLAYER_SHIELD value by 20 pixels from the
  1801.     ;full "game_levels" image.
  1802.     ;For example, if the player has 100 points of PLAYER_SHIELD left, then we would want to draw the first
  1803.     ;100*20 pixels from the left of the image. 
  1804.     ;The DRAWIMAGERECT(rectangle) command will do this for us! It requires the following parameters:
  1805.     ;Image name, X-coordinate on-screen, Y-coordinate on-screen,
  1806.     ;top left x and y coordinates on the "game_levels" image and bottom right x and y coordinates
  1807.     DrawImageRect game_levels,SCREEN_WIDTH-206,236,0,0,Int(PLAYER_SHIELD),20
  1808.  
  1809.     ;do the same for CLOAK and BOOSTERS display
  1810.     DrawImage game_cloak,SCREEN_WIDTH-210,273
  1811.     DrawImageRect game_levels,SCREEN_WIDTH-206,286,0,0,Int(PLAYER_CLOAK),20
  1812.     DrawImage game_boosters,SCREEN_WIDTH-210,323
  1813.     DrawImageRect game_levels,SCREEN_WIDTH-206,336,0,0,Int(PLAYER_BOOSTERS),20
  1814.     
  1815.         ;notice that by using a calculated x coordinate "SCREEN_WIDTH - value" in conjunction with a fixed
  1816.         ;y coordinate, we will have the HUD images at the same distance from the top right of the screen
  1817.         ;in any Graphics resolution we choose
  1818.     
  1819.     ;the JUMPS box is slightly different, because it is not a solid bar.
  1820.     ;it is actually 5 different prerendered images    
  1821.     DrawImage game_jumps,SCREEN_WIDTH-210,373
  1822.  
  1823.     If PLAYER_JUMPS >= 1 Then                                ;this line says that if the player has 1 or more JUMPS left
  1824.         DrawImage game_jumps_level(1),SCREEN_WIDTH-205,389    ;then draw the leftmost JUMP indicator (at the calculated position)
  1825.     End If
  1826.     If PLAYER_JUMPS >= 2 Then                                ;if the player has 2 or more jumps left then draw
  1827.         DrawImage game_jumps_level(2),SCREEN_WIDTH-166,389    ;the second JUMP indicator. Obviously, if the player has 2 JUMPs
  1828.                                                             ;left then he will also have "1 or more jumps left", so the first
  1829.                                                             ;IF will fire as well as this one..
  1830.     End If
  1831.     If PLAYER_JUMPS >= 3 Then                                ;do the same for 3, 4 and 5 (which is the maximum number allowed)
  1832.         DrawImage game_jumps_level(3),SCREEN_WIDTH-127,389
  1833.     End If
  1834.     If PLAYER_JUMPS >= 4 Then
  1835.         DrawImage game_jumps_level(4),SCREEN_WIDTH-88,389
  1836.     End If
  1837.     If PLAYER_JUMPS >= 5 Then
  1838.         DrawImage game_jumps_level(5),SCREEN_WIDTH-49,389
  1839.     End If
  1840.     
  1841.     ;draw the SCORE and HISCORE boxes
  1842.     DrawImage game_score,10,SCREEN_HEIGHT-51
  1843.     DrawImage game_hiscore,230,SCREEN_HEIGHT-51
  1844.  
  1845.     ;remember this from "menu_draw_update()" where we built the HI and LAST SCORES out of the Strings
  1846.     ;by drawing the first character, then the second etc.. in a horizontally stepped increment?
  1847.     ;this is exactly the same code, but with slightly different coordinates and a different "font" AnimImage
  1848.     ;(which is "see through" like the blue boxes)
  1849.     For i = 1 To 7
  1850.         DrawImage game_scorefont,32+((i-1)*24),SCREEN_HEIGHT-35,Int(Mid(PLAYER_SCORE_STR,i,1))
  1851.         DrawImage game_scorefont,252+((i-1)*24),SCREEN_HEIGHT-35,Int(Mid(HI_SCORE_STR,i,1))
  1852.     Next
  1853.     
  1854.     ;this next bit of code draws the coloured dots on the radar
  1855.     ;by using their game map coordinates, at a ratio to the size of the radar box graphic
  1856.     For icon.icons=Each icons
  1857.         ;this draws each of the icons
  1858.         DrawImage game_icon_dot,((SCREEN_WIDTH-211)+icon\x/(GAME_AREA_X/200)),((9)+icon\y/(GAME_AREA_Y/200))
  1859.     Next
  1860.     For enemy.enemies=Each enemies
  1861.         ;this draws each of the enemies
  1862.         DrawImage game_enemy1_dot,((SCREEN_WIDTH-211)+enemy\x/(GAME_AREA_X/200)),((9)+enemy\y/(GAME_AREA_Y/200))
  1863.     Next
  1864.     
  1865.     ;this next bit draws the player's green dot on the radar
  1866.     If hypercount = 0 And cloakon=0 Then    ;if both the "hypercount" and "cloakon" features are inactive (i.e.: normal play)
  1867.         ;then permanently draw the player's radar dot
  1868.         DrawImage game_player_dot,((SCREEN_WIDTH-211)+PLAYER_X/(GAME_AREA_X/200)),((9)+PLAYER_Y/(GAME_AREA_Y/200))
  1869.  
  1870.     ElseIf hypercount = 0 And (cloakon/2 = Int(cloakon/2)) Then
  1871.         ;otherwise, if the cloakon value is EVEN, draw the dot (flickery effect again)
  1872.         ;but if the hypercount value isn't 0 (we're in the middle of a hyperjump) then don't do this..
  1873.         ;.. consequently, even though the player's position moves on the radar map during a hyperjump,
  1874.         ;and it affects the enemies, don't show this to the user!
  1875.         DrawImage game_player_dot,((SCREEN_WIDTH-211)+PLAYER_X/(GAME_AREA_X/200)),((9)+PLAYER_Y/(GAME_AREA_Y/200))
  1876.     End If
  1877.  
  1878.     ;if the game is paused (FLAG_PAUSE = 1) then draw the image when "game_pause_stat" = 1
  1879.     ;this gives us our flash on-off effect as used earlier in "menu_draw_update()"
  1880.     If FLAG_PAUSE = 1 And game_pause_stat = 1 Then
  1881.         DrawImage game_paused,SCREEN_WIDTH/2-ImageWidth(game_paused)/2,SCREEN_HEIGHT-((SCREEN_HEIGHT-350)/2+ImageHeight(game_paused)/2)
  1882.     End If
  1883.     
  1884.     ;exactly the same during a "GAME OVER" scenario
  1885.     If gameovercounter > 1 And gameoverstat = 1 Then
  1886.         DrawImage game_gameover,SCREEN_WIDTH/2-ImageWidth(game_gameover)/2,SCREEN_HEIGHT-((SCREEN_HEIGHT-350)/2+ImageHeight(game_gameover)/2)
  1887.     End If
  1888.  
  1889.     ;the following text will only be printed on the screen while the "FLAG_DEBUG" variable is set to 1 (F1, as I programmed it, on the main menu!)
  1890.     If FLAG_DEBUG = 1 Then
  1891.         ;the TEXT command writes a STRING of text onto the screen at the given coordinates in the currently set font
  1892.         ;as I haven't used the LoadFont or SetFont commands, this will just be Blitz' default font.
  1893.  
  1894.         Color 255,255,255                                    ;just in case, set the colo(u)r of the text to WHITE (255, 255, 255)
  1895.         Text 0,0,"PLAYER ANGLE = " + PLAYER_ANGLE                ;"Write the string 'PLAYER ANGLE = ' followed by the number held in PLAYER_ANGLE"
  1896.         Text 0,20,"PLAYER SPEED = " + PLAYER_SPEED
  1897.         Text 0,40,PLAYER_ANGLE + " / 5 = " + PLAYER_ANGLE/5
  1898.         Text 0,60,"SHIPFRAME = " + game_player_frame
  1899.         Text 0,80,"CO-ORDS = " + Int(PLAYER_X)
  1900.         Text 140,80," , " 
  1901.         Text 160,80,Int(PLAYER_Y)
  1902.         Text 0,100, "whichway = " + whichway
  1903.         Text 0,120, "SCORE = " + PLAYER_SCORE
  1904.         Text 0,140, "SCORESTR = " + PLAYER_SCORE_STR
  1905.  
  1906.         ;this debug code counts how many bullets are "active" in the array (their 'style' - bullets(i,4) is not 0
  1907.         ;this was useful for deciding how big the array needed to be for the game, i.e.: how many bullets array
  1908.         ;containers would be in use at any one time.
  1909.         ;in reality, during the game, this value rarely gets above 100 active bullets,
  1910.         ;but I kept the "available" bullets (bulletnum) at 500 anyway.
  1911.         
  1912.         ;if you needed better performance, then decreasing the value of "bulletnum" might increase the speed of the program!
  1913.         bulletcount = 0
  1914.         For i = 0 To bulletnum-1
  1915.             If bullets(i,4) > 0 Then
  1916.                 bulletcount = bulletcount + 1
  1917.             End If
  1918.         Next
  1919.         Text 0,160, "BULLETS = " + bulletcount
  1920.         Text 0,180, "P.E.F. = " + player_explosion_frame
  1921.         i = 0
  1922.         ;write some of the information about each of our enemies at the bottom of the screen.
  1923.         ;this was incredibly useful when working out the A.I. code, 'cos you could see in "words" what
  1924.         ;each enemy was doing, even when it wasn't on the screen!
  1925.         For enemy.enemies=Each enemies
  1926.             Text 20,((20*i)+380),i+1
  1927.             Text 40,((20*i)+380),enemy\angle
  1928.             Text 80,((20*i)+380),enemy\dest_angle
  1929.             Text 110,((20*i)+380),"y="+enemy\dest_opp
  1930.             Text 210,((20*i)+380),"x="+enemy\dest_adj
  1931.             Text 310,((20*i)+380),"hyp="+enemy\dest_hyp
  1932.             Text 430,((20*i)+380),enemy\rotate_angle
  1933.             Text 470,((20*i)+380),enemy\energy
  1934.             Text 510,((20*i)+380),enemy\exp_frame
  1935.             Text 610,((20*i)+380),enemy\gen
  1936.             Text (((SCREEN_WIDTH/2)-ImageWidth(game_enemy1)/2) - (PLAYER_X - enemy\x)), (((SCREEN_HEIGHT/2)-ImageWidth(game_enemy1)/2) - (PLAYER_Y - enemy\y)),i+1
  1937.             i = i + 1
  1938.         Next
  1939.     End If
  1940.     
  1941.     ;just like in "menu_draw_update()", the user can press a key which just makes the value of "FLAG_SCREENSAVE" equal 1.
  1942.     ;when the code gets to here, it saves out the named Buffer as a BMP picture.
  1943.     If FLAG_SAVESCREEN=1 Then
  1944.         SaveBuffer (BackBuffer(),"CRGameScreen.bmp")
  1945.         FLAG_SAVESCREEN = 0
  1946.     End If 
  1947.     
  1948.     Flip                    ;as before in "menu_draw_update()", FLIP everything we've just drawn on the backbuffer and show it on the frontbuffer, i.e.: your monitor!!
  1949. End Function
  1950.  
  1951. ;a little function which randomizes the x and y coordinates of each version of the "stars" Type, plus it's "depth" property
  1952. Function game_stars_randomize()
  1953.     For star.stars=Each stars
  1954.         star\x=Rnd(-5,SCREEN_WIDTH)            ;create random x and y positions for all the stars
  1955.         star\y=Rnd(-5,SCREEN_HEIGHT)
  1956.         star\depth=Rnd(1,5)                    ;the depth of the stars results in our sexy parallex effect
  1957.     Next
  1958. End Function
  1959.  
  1960. ;an even littler function which just gives us random x and y coordinates for the player.
  1961. Function game_player_randomize()
  1962.     PLAYER_X = Rand(0,GAME_AREA_X)
  1963.     PLAYER_Y = Rand(0,GAME_AREA_Y)
  1964. End Function
  1965.  
  1966.  
  1967. ;This is the last function and it's MARVELLOUS! :)
  1968. ;This is the type of function that you should proactively *try* to write, because they're incredibly simple, yet incredibly effective
  1969. ;and they impress the girls, I can tell you... Um.. No.. That's a lie..
  1970.  
  1971. ;anyway the beauty of this function is that when you call it in the code above, you "feed" it some parameters.
  1972. ;this one is expecting an X Coordinate, a Y Coordinate, an Angle value, a Speed value and a Style value.
  1973. ;it doesn't care who or what they refer to, it just knows that it wants 5 numbers to work with.
  1974.  
  1975. ;So, when a player requires two bullets to be made, I just give it "PLAYER_X, PLAYER_Y, PLAYER_ANGLE,
  1976. ;PLAYER_SPEED and 1 (which just makes sure the correct bullet AnimImage is used!)
  1977.  
  1978. ;When an enemy needs a bullet, I just give it "Enemy X, Enemy Y, Enemy Angle, Enemy Speed, 2"
  1979.  
  1980. ;the createbullet() function does the rest and "produces" 2 bullets on the screen, starting at the end of the calling ship's laser.. BUT THAT'S ALL..
  1981. ;After the bullet has been created, its "life" is calculated in another part of the code (it's x and y coordinates are altered based on the original angle and speed
  1982. ;calculated in this function..) Enjoy
  1983.  
  1984. Function createbullet(x,y,angle,speed,style) ;creates 2 bullets starting on the end of a ship's lasers.
  1985.  
  1986.     ;there are "bulletnum" containers available in the "bullets()" array.
  1987.     ;if we've reached the maximum number of bullets, then the very first
  1988.     ;'bullet' will be overwritten with this new bullet. 
  1989.     ;We do this by wrapping "nextbullet" back to 0, when it reaches bulletnum
  1990.     If nextbullet = bulletnum-1 Then
  1991.         nextbullet = 0
  1992.     End If
  1993.     
  1994.     ;we want to create a bullet for the RIGHT laser of a ship
  1995.     ;by messing with the angleoffset value during debugging, I was able to come up with the
  1996.     ;correct values that looked right on screen (30 for this angle and 28 for the next calculation)
  1997.     angleoffset = angle - 30
  1998.     bullets(nextbullet,0) = x + 28*Cos(angleoffset)        ;this sets the x and y pixel offset from the ship's game coordinates
  1999.     bullets(nextbullet,1) = y + 28*Sin(angleoffset)        ;in this case 28*Cos/Sin of the angle offset
  2000.  
  2001.     ;these next bits are just setting the origin of the bullets, including it's start position, speed and angle
  2002.     ;this is so the bullets can fly independently of the PLAYER's ship's Angle and speed (unlike everything else in the game)
  2003.     bullets(nextbullet,2) = angle
  2004.     If speed <= 0 Then                        ;this bit essentially stops the player catching up to his bullets, or bullets flying backwards
  2005.         bullets(nextbullet,3) = 25            ;if the ship is still, or moving backwards, then a bullet fires off at a speed of 25
  2006.     Else
  2007.         bullets(nextbullet,3) = speed + 25    ;otherwise, if a ship is moving forwards, then the bullet flys off at a speed of 25, PLUS the ship's speed
  2008.     End If
  2009.  
  2010.     bullets(nextbullet,4) = style                    ;used to decide which bullet AnimImage should be used
  2011.     bullets(nextbullet,5) = 0                            ;used to keep track of the frame of animation a bullet is on
  2012.     bullets(nextbullet,6) = bullets(nextbullet,0)        ;used to know where a bullet began it's life in x and y coordinates
  2013.     bullets(nextbullet,7) = bullets(nextbullet,1)
  2014.     nextbullet = nextbullet+1                        ;we've successfully created a bullet (whose 'life' from now on will be calculated back
  2015.                                                     ;in "game_loop_update()", so now we move the "nextbullet" value on by 1
  2016.                                                     ;ready for creation of the next bullet!
  2017.  
  2018.  
  2019.  
  2020.     If nextbullet = bulletnum-1 Then                    ;exactly the same process, but with a 120 degree offset for the left hand laser
  2021.         nextbullet = 0
  2022.     End If
  2023.     angleoffset = angle - 150
  2024.     bullets(nextbullet,0) = x + 28*Cos(angleoffset)
  2025.     bullets(nextbullet,1) = y + 28*Sin(angleoffset)
  2026.     bullets(nextbullet,2) = angle
  2027.     If speed <= 0 Then
  2028.         bullets(nextbullet,3) = 25
  2029.     Else
  2030.         bullets(nextbullet,3) = speed + 25
  2031.     End If
  2032.     bullets(nextbullet,4) = style
  2033.     bullets(nextbullet,5) = 0
  2034.     bullets(nextbullet,6) = bullets(nextbullet,0)
  2035.     bullets(nextbullet,7) = bullets(nextbullet,1)
  2036.     nextbullet = nextbullet+1
  2037. End Function